犹记得小学年代学奥术就曾经被喝汽水问题支配,没有想到现在这么大了还要面对这道题。
题一:
1元钱一瓶汽水,喝完之后两个空瓶换一瓶汽水。 问:若你有N元钱,你最多能喝多少瓶汽水?
题二:
一个人买汽水,一块钱一瓶汽水,三个瓶盖可以换一瓶汽水,两个空瓶可以换一瓶汽水,问20块钱可以买多少汽水?
目录
题一
思路1:(递归)
- 先喝掉所有汽水,然后把空瓶换成汽水 - 重复操作,直到手上只有一瓶汽水,喝掉扔瓶子使用递归的思想即可实现:
public static int q1s1(int n){
//若手上只有一瓶 那么只能喝到一瓶
if (n==1){
return 1;
}else{
//喝掉汽水,空瓶换水继续喝!
return n+q1s1(n/2);
}
}
等等!有个问题!
这样每次剩奇数个空瓶,你不就把多的那个给扔了吗
多可惜!!!!!!(主要是算不到正确答案了)
那怎么办?告诉下一步我有没有剩一个空瓶就不好了?
public static int q1s1(int n,int i){
//若手上只有一瓶 且没有空瓶 那么只能喝到一瓶
if (n==1&&i==0){
return 1;
}else if(n==1){
//如果手上有一瓶汽水和一个空瓶 能喝到两瓶
return 2;
}else{
//把这轮喝剩的空瓶和上轮可能剩下的空瓶尽可能换成汽水
//把可能剩下的空瓶传递给下一次
return n+q1s1((i+n)/2, (i+n)%2);
}
}
看起来有点晕?
耍个心机简化一下!
如果手里是奇数瓶,就留一瓶下一轮喝,不就不用多个参数记录空瓶了? public static int q1s2(int n){
//若手上只有一瓶 那么只能喝到一瓶
if (n==1){
return 1;
}else if(n%2==0){
//偶数瓶!刚好可以换
return n+q1s2(n/2);
}else{
//奇数瓶?留一瓶下一轮喝!
return (n-1)+q1s2(n/2+1);
}
}
思路2:(递归)
假设现在手上有20块,我喝了39瓶,刚想扔瓶子
等等!地上有谁掉的一块钱!
我这多出来的一块钱又可以多喝两瓶汽水了!那么知道20块能喝多少瓶汽水的情况下 21块能喝多少不是很简单?
也可以理解为:①先买一瓶喝一瓶,②再买一瓶喝一瓶,③两个空瓶换一瓶喝一瓶,重复23直到钱花完只剩一个空瓶
public static int q1s3(int n){
//若手上只有一瓶 那么只能喝到一瓶
if (n==1){
return 1;
}else{
return 2+q1s3(n-1);
}
}
思路3:(数学)
小明同学小脑瓜一转:
一元买一瓶汽水,两个空瓶换一瓶汽水
一元=一瓶汽水=两个空瓶→空瓶=0.5元
也就是说,一瓶汽水的水=0.5元!
最后会扔掉一个空瓶子就等于扔掉了五毛钱(心疼)
那除去五毛钱剩下的钱不就全部拿来买快乐水了吗?
于是:一行解决:
public static int q1s4(int n){
//手上有几个五毛钱拿来买水了呢?
//(n-0.5)/0.5
return n*2-1;
}
题二
多了三个瓶盖换一瓶汽水的操作 肥宅又能多喝几瓶汽水了呢!
思路1:(递归)
和题一思路类似
如果要用题一中第一种实现形式实现:在传递空瓶数的基础上再传递一个瓶盖数:
public static int q2s1(int n,int i,int j){
//若手上只有一瓶 且没有空瓶 且 瓶盖数小于等于1 那么只能喝到一瓶
if (n==1&&i==0&&j<=1){
return 1;
}else{
//空瓶瓶盖能换汽水的瓶数(n+i)/2+(n+j)/3 剩余空瓶数(n+i)%2 剩余瓶盖数(n+j)%3
return n+q2s1((n+i)/2+(n+j)/3,(n+i)%2,(n+j)%3);
}
}
如果要用题一中第二种实现形式实现,题一中两瓶两瓶喝即可保证不剩空瓶,而题二中需要六瓶六瓶喝才能保证不剩余空瓶和瓶盖不剩,六瓶以内还要单独判断/计算
public static int q2s2(int n){
//若手上少于6瓶,则分开讨论、计算
if (n<6){
switch (n){
case 1:
return 1;
case 2:
return 5;
case 3:
return 11;
case 4:
return 17;
case 5:
return 23;
}
return -9999;
}else{
//若手上大于或者等于六瓶,则以六的倍数喝汽水,并把空瓶和瓶盖换成汽水和多的汽水喝下一轮
return (n-n%6)+q2s2(n-(n-n%6)/6);
}
思路2:(递归)
题一中可以预见到,不论之前有多少钱,都是剩余一个空瓶,所以多一块钱都是稳定能够多喝2瓶,
但是在题二中,可能剩一个空瓶+一个瓶盖或者一个空瓶+两个瓶盖,怎么办呢?
可以通过之前喝了多少来算出剩几个瓶盖!
以为瓶盖都是三个三个换的,因此剩余的瓶盖数即为之前喝的汽水数对3取余!
- 1空瓶+1瓶盖+捡到的1块钱
- 多喝一瓶 剩2空瓶2瓶盖 2空瓶换一个汽水
- 再多喝一瓶 剩1空瓶3瓶盖 3瓶盖又能换一个汽水
- 又双叒叕喝一瓶 剩2空瓶1瓶盖 2空瓶换一个汽水
- 最后一瓶 剩1空瓶2瓶盖
- 一块钱一共多喝了4瓶汽水
- 1空瓶+2瓶盖+捡到的1块钱
- 多喝1瓶 剩2空瓶3瓶盖 2空瓶3瓶盖换2汽水
- 再喝2瓶 剩2空瓶2瓶盖 2空瓶换1汽水
- 又多喝1瓶 剩1空瓶3瓶盖 3瓶盖换1汽水
- 继续喝1瓶 剩2空瓶1瓶盖 2空瓶换1汽水
- 最后喝1瓶 剩1空瓶2瓶盖
- 一块钱多喝了6瓶汽水
除了1块钱再捡一块是多喝了4瓶,以后每捡一块都多喝六瓶
public static int q2s3(int n){
//若手上只有一瓶 那么只能喝到一瓶
if (n==1){
return 1;
}else{
int temp=q2s3(n-1);
if (temp%3==1){
//如果剩一个瓶盖则多喝4瓶
return temp+4;
}else {
//如果剩两个瓶盖则多喝6瓶
return temp+6;
}
}
}
思路3:(数学)
其实通过上面分析以及可以得出:s1=1,s2=5,sn=6n-7(n>=2)
和题一中同理我们可以得出:瓶子1/2元 瓶盖1/3元 汽水1/6元
最后剩下1瓶子1或者2瓶盖就是5/6或者7/6元
public static int q2s4(int n){
//手上有几个1/6 扣去瓶子和2个瓶盖钱(假设是两个瓶盖)
int maybe=6*n-3-4;
//验证 是否正好剩两个瓶盖
if (maybe%3==2){
//如果所喝过的汽水数除以3余2则验证成功
return maybe;
}else{
//否则就是剩余1瓶子1瓶盖 把多扣的1瓶盖钱,对应2汽水加回去
return maybe+2;
}
}
彩蛋
明明算到瓶盖和空瓶老值钱了但是却只能扔掉,有没有感觉很可惜
有办法!
- 如果你是题一中的小盆友
找你的小伙伴借一个空瓶子 换了汽水喝掉再还给他
多喝一瓶不浪费
- 如果你是题二中的小盆友