一个简单的24点程序
下面本文将通过两个题目实例,分别给出用递归方法和循环方法的解决方案以及解题思路,便于读者更好地掌握两种方法。首先是一个简单的计算24点的问题(为了简化问题,我们假设只使用求和计算方法):
从1-9中任选四个数字(数字可以有重复),使四个数字的和刚好是24。
题目很简单,数字都是个位数,可以重复且之用加法,循环算法的核心就是使用四重循环穷举所有的数字组合,对每一个数字组合进行求和,判断是否是24。使用循环的版本可能是这个样子:
8constunsignedintNUMBER_COUNT=4;//9 9constintNUM_MIN_VALUE=1; 10constintNUM_MAX_VALUE=9; 11constunsignedintFULL_NUMBER_VALUE=24;//45; 40voidPrintAllSResult(void) 41{ 42inti,j,k,l; 43intnumbers[NUMBER_COUNT]={0}; 44 45for(i=NUM_MIN_VALUE;i<=NUM_MAX_VALUE;i++) 46{ 47 numbers[0]=i;/*确定第一个数字*/ 48 for(j=NUM_MIN_VALUE;j<=NUM_MAX_VALUE;j++) 49 { 50 numbers[1]=j;/*确定第二个数字*/ 51 for(k=NUM_MIN_VALUE;k<=NUM_MAX_VALUE;k++) 52 { 53 numbers[2]=k;/*确定第三个数字*/ 54 for(l=NUM_MIN_VALUE;l<=NUM_MAX_VALUE;l++) 55 { 56 numbers[3]=l;/*确定第四个数字*/ 57 if(CalcNumbersSum(numbers,NUMBER_COUNT)==FULL_NUMBER_VALUE) 58 { 59 PrintNumbers(numbers,NUMBER_COUNT); 60 } 61 } 62 } 63 } 64} 65} |
这个PrintAllSResult()函数看起来中规中矩,但是本人的编码习惯很少在一个函数中使用超过两重的循环,更何况,如果题目修改一下,改成9个数字求和是45的组合序列,就要使用9重循环,这将使PrintAllSResult()函数变成臭不可闻的垃圾代码。
现在看看如何用递归方法解决这个问题。递归方法的解题思路就是对题目规模进行分解,将四个数字的求和变成三个数字的求和,两个数字的求和,当最终变成一个数字时,就达到了递归终止条件。这个题目的递归解法非常优雅:
67voidEnumNumbers(int*numbers,intlevel,inttotal) 68{ 69inti; 70 71for(i=NUM_MIN_VALUE;i<=NUM_MAX_VALUE;i++) 72{ 73 numbers[level]=i; 74 if(level==(NUMBER_COUNT-1)) 75 { 76 if(i==total) 77 { 78 PrintNumbers(numbers,NUMBER_COUNT); 79 } 80 } 81 else 82 { 83 EnumNumbers(numbers,level+1,total-i); 84 } 85} 86} 87 88voidPrintAllSResult2(void) 89{ 90intnumbers[NUMBER_COUNT]={0}; 91 92 EnumNumbers(numbers,0,FULL_NUMBER_VALUE); 93} |
如果题目改成“9个数字求和是45的组合序列”,只需将NUMBER_COUNT的值改成9,FULL_NUMBER_VALUE的值改成45即可,算法主体部分不需做任何修改。