现在有N元钱,两块钱一瓶,或者直接给你N瓶酒,两个空瓶换一瓶酒,四个瓶盖换一瓶酒,问你最后可以喝多少瓶?如果能借酒呢?

问题描述:现在有N元钱,两块钱一瓶,或者直接给你N瓶酒,两个空瓶换一瓶酒,四个瓶盖换一瓶酒,问你最后可以喝多少瓶?如果能借酒呢?

解决思路1:

N元钱,其实就是N/2瓶酒。所以我们在程序中直接使用N瓶酒进行计算,直接使用递归,直到最后余下的酒瓶和瓶盖不够换酒。但是要注意:每次换酒后可能会剩下酒瓶和瓶盖,比如3个酒瓶和5个瓶盖,拿出2个酒瓶和4个瓶盖换完2瓶酒,剩下1个酒瓶和1个瓶盖,需要“存”起来,可以和下一轮新增的酒瓶和瓶盖一起换酒。代码如下

import java.util.Scanner;

public class Cnt_N_Beer {
//    存储每一次换完酒剩余的酒瓶和瓶盖
    static int bottle = 0;
    static int cap = 0;
    static int beer(int n){
//        使用当前的酒+酒瓶+瓶盖计算可以换的酒
        int re_n = (bottle+n)/2 + (cap+n)/4;
        bottle = (bottle+n)%2;
        cap = (cap+n)%4;
//        结束条件是换不了酒,那么直接返回,结束递归
        if(re_n == 0){
            return n;
        }
        return n+beer(re_n);
    }
    public static void main(String[] args) {
        Scanner user = new Scanner(System.in);
        System.out.print("please input an integer:");
        int n = user.nextInt();
        int beer_cnt;
//        如果啤酒数量不够两瓶,没得换,直接返回啤酒数量
        if((n<=1) && (n>=0)) {
            beer_cnt = n;
            bottle = n;
            cap = n;
            System.out.println("beer is " + beer_cnt);
//        如果输入的啤酒数量为负数,提示
        }else if (n<0){
            System.out.println("beer count can't be negative");
        }else {
//        使用beer方法递归计算
            beer_cnt = beer(n);
            System.out.println("beer is " + beer_cnt);
        }
//        输出最后剩余的酒瓶数和瓶盖数
        System.out.println("bottle is " + bottle);
        System.out.println("cap is " + cap);
    }
}

几个测试结果如下

      

不知道你有没有发现,不管酒的数量是多少,最后剩下的酒瓶都是1个,瓶盖数是3个 ,等会第二种解决方案会用到这个性质。那么我们是不是可以验证一下,是不是真的每一次都会剩余1个酒瓶,3个瓶盖?使用do_while循环验证如下。

public class Cnt_N_Beer {
//    存储每一次换完酒剩余的酒瓶和瓶盖
    static int bottle = 0;
    static int cap = 0;
    static int beer(int n){
//        使用当前的酒+酒瓶+瓶盖计算可以换的酒
        int re_n = (bottle+n)/2 + (cap+n)/4;
        bottle = (bottle+n)%2;
        cap = (cap+n)%4;
//        结束条件是换不了酒,那么直接返回,结束递归
        if(re_n == 0){
            return n;
        }
        return n+beer(re_n);
    }
    public static void main(String[] args) {

        int n = 1;
        int loop = 500000;
        do{
            n++;
            beer(n);
        }while(((bottle==1) && (cap==3)) && (n<loop));
        System.out.println(n);
    }
}

 测试结果如下,每次都是因为达到了循环次数而退出,如果不加循环次数那么它会一直循环计算。说明每次运行beer()方法后都剩余1个酒瓶,3个瓶盖

解决思路2

        两个酒瓶换一瓶酒,四个瓶盖可以换一瓶酒,然后一瓶酒是2元,所以一个瓶盖的价值是5角,一个酒瓶的价值是1元,那么相当于我们花5角钱就可以喝到一瓶酒,结果是这样吗,我们看一看如果是6元钱,首先可以买3瓶酒,根据思路1的运行结果,我们知道最后可以喝到7瓶酒,按照5角一瓶酒,6元钱我们不是可以喝12瓶酒吗?哪里出问题了?

        这里就要提到思路1中的最后一句话,每次最后都会剩下1个酒瓶和3个瓶盖,所以我们是有2.5元浪费的,这2.5元换不了酒。所以每次计算需要先减去2.5元,然后再根据5角一瓶,计算最后可以喝多少酒?还要注意:如果钱是11.9,那么只能买5瓶酒,所以要先将输入的浮点数转为2的倍数的整数,也就是说11.9变为10,14.8变为14,代码如下

import java.util.Scanner;

public class Money_N_Beer {
    public static void main(String[] args) {
        Scanner user = new Scanner(System.in);
        System.out.print("please input your money:");
        double real_money = user.nextDouble();
//        将输入的浮点数转为整数,如11.9变成11
        int int_money = (int)real_money;
        /**
         * 虽然已经是整数,但是仍然会存在不够买酒而多余1元,
         * 所以先除2得到能买酒的数量,然后再乘2转为钱
         * 所以此时得到的money只会是偶数 0,2,4,6……
         */
        int money = int_money/2*2;

//        如果钱不够2元,买不了酒
        if(money<2) {
            System.out.println("money is so little, can't buy beer");
//        如果money>=2 && money<4,那么只能买一瓶酒,最后不存在浪费2.5元,要特殊考虑
        }else if(money<4){
            System.out.println("beer is " + (money/2));
            System.out.println("bottle is " + (money/2));
            System.out.println("cap is " + (money/2));
        }else {
            int beer = (int)((money-2.5)/0.5);
            System.out.println("beer is " + beer);
            System.out.println("bottle is 1");
            System.out.println("cap is 3");
        }

    }
}

几个测试结果如下

 

    

拓展:如果可以借酒呢?

这个是网页上经常看到的问题,按照我们上面的测试,不管多少瓶酒(大于1瓶酒),最后剩余的酒瓶都是1个,瓶盖都是3个,如果可以借酒,借1瓶酒,那么喝完酒变为2个酒瓶,4个瓶盖。可以换2瓶酒,酒喝完后有2个酒瓶,2个瓶盖,可以用2个酒瓶接着换1瓶酒,喝完后剩余1个酒瓶,3个瓶盖,结束。也就是借1瓶酒,我们可以喝4瓶酒,除去借的,我们可以多喝3瓶酒。如果可以一直借,那么可以一直喝下去。新增代码如下红色框代码

 运行测试结果如下,每一次借酒都会增加3瓶酒

   

猜你喜欢

转载自blog.csdn.net/yldmkx/article/details/109380446