蓝桥杯_第五届_李白打酒

【问题描述】

    话说大诗人李白,一生好饮。幸好他从不开车。

 

    一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱:

 

    无事街上走,提壶去打酒。

    逢店加一倍,遇花喝一斗。

 

    这一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,他正好把酒喝光了。 

 

    请你计算李白遇到店和花的次序,可以把遇店记为a,遇花记为b。则:babaabbabbabbbb 就是合理的次序。像这样的答案一共有多少呢?请你计算出所有可能方案的个数(包含题目给出的)。

 

【问题分析】

穷举算法: 问题描述中给出了一种合理序列babaabbabbabbbb,实际程序中处理二进制数据更方便,我们用0代替a,1代替b,前面的字符串序列可表示为101001101101111,最后一位已经确定肯定为1,只要对前14位中0和1的所有排列组合进行穷举即可。在穷举过程中对每种可能序列进行检查,如果符合以下条件则是一种可能的序列:

(1)最终序列中含有十个1(或五个0)。

(2)根据序列推算,最终酒壶中刚好没有酒。

下面的问题就是如何对14位0和1的所有排列组合进行穷举。当然方法有很多,这里介绍一种利用整数转换成二进制数的方法来穷举所有可能性。由五个0和九个1组成的最小二进制数是00000111111111(十进制数511),最大二进制数是11111111100000(十进制数16352),由此确定了整数穷举的范围。在整数穷举过程中,再使用Integer.toBinaryString()方法将整数转换为二进制数,对于转换后的二进制数不足14位的可以前补0。

【程序代码】

 1 public class 蓝桥杯_第五届_李白打酒
 2 {
 3     public static void main(String[] args) {
 4         // TODO Auto-generated method stub
 5 
 6         int count=0;//方案个数计数器
 7         
 8         //对所有可能方案进行穷举,0代表店,1代表花
 9         for(int i=Integer.parseInt("00000111111111", 2);i<=Integer.parseInt("11111111100000", 2);i++)
10         {
11             //将整数转换为二进制字符串,由于最后肯定是花,所以最后一位连接一个1
12             String str=Integer.toBinaryString(i)+"1";
13             
14             //如果字符串不足15位,前补0
15             int t=15-str.length();
16             for(int j=0;j<t;j++)
17             {
18                 str="0"+str;
19             }
20             //str=String.format("%015d",Long.parseLong(str));
21             
22             //测试字符串中是否含有10个1(即10个花)
23             //符合这个条件才有可能是其中一个解
24             if(ten_one(str))
25             {
26                 int jh=2;//酒壶里开始有2斗酒
27                 
28                 //对当前字符串序列按"遇店(0)加一倍,遇花(1)喝一斗"
29                 //推算酒壶最后的剩余酒量
30                 for(int j=0;j<str.length();j++)
31                 {
32                     if(str.charAt(j)=='1')
33                     {
34                         jh-=1;
35                     }
36                     else
37                     {
38                         jh*=2;
39                     }
40                 }
41                 
42                 //如果最后酒壶中没酒,
43                 //就是一种可能的方案,计数器加1
44                 if(jh==0)
45                 {
46                     count++;
47                     //System.out.println(str);
48                 }
49             }
50         }
51         System.out.println(count);
52     }
53     
54     //判断字符串中是否含有10个1
55     //是,返回true,否,返回false
56     private static boolean ten_one(String str) {
57         
58         int cc=0;
59         for(int i=0;i<str.length();i++)
60         {
61             if(str.charAt(i)=='1')
62                 cc++;
63         }
64         if(cc==10)
65             return true;
66         return false;
67     }
68 }

 

【运行结果】

14

 

【相关知识】

数制转换

字符串特定字符计数

基数为2的排列组合

 

【总结】

解决这个问题最难的就是0和1的所有排列组合的穷举,每个位置上的字符变化只有两种情况(0和1,或者问题描述中所说的a和b),程序中使用的方法可以扩展到每个字符位置上的变化更多的情况,如0、1、2三种情况,可以使用三进制,那就在三进制和十进制之间进行转换。x进制转换为十进制的方式是Integer.parseInt("x进制字符串",x),十进制转换为x进制字符串的方法是Integer.toString(十进制整数,x)。 

以上方法适合于字符位数比较多的情况,如果就两三位字符长度,那就用两层或三层循环嵌套就可以解决。

posted @ 2015-03-26 18:11  #码农#  阅读(742)  评论(0编辑  收藏  举报