浅谈喝汽水问题————能用数学解决为什么要用递归

犹记得小学年代学奥术就曾经被喝汽水问题支配,没有想到现在这么大了还要面对这道题。

题一:

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;
        }
    }

彩蛋

明明算到瓶盖和空瓶老值钱了但是却只能扔掉,有没有感觉很可惜

有办法!

  • 如果你是题一中的小盆友
找你的小伙伴借一个空瓶子 换了汽水喝掉再还给他

多喝一瓶不浪费

在这里插入图片描述

  • 如果你是题二中的小盆友
找你的小伙伴借一个空瓶子+两个瓶盖
两个瓶子四个瓶盖

可以多喝7瓶还剩一个空瓶子+两个瓶盖 还给好兄弟

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值