蓝桥杯_第五届_李白打酒
【问题描述】
话说大诗人李白,一生好饮。幸好他从不开车。
一天,他提着酒壶,从家里出来,酒壶中有酒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)。
以上方法适合于字符位数比较多的情况,如果就两三位字符长度,那就用两层或三层循环嵌套就可以解决。