《编程之美》1.16是对24点游戏实现的分析。24点游戏是一款非常大众化的智力游戏,规则很简单,给出4个在1~13间的数字,通过加减乘除四则运算使四个数字的运算结果为24。现在需要编程实现求解24点游戏的表达式。
最初没有看书中所给出的实现代码,想到的最简单最直接的方法就是穷举。这里,我们需要事先考虑到这个游戏的一些约束条件,由于加减乘除均为二元运算,每次选出两个数字进行计算,计算的结果和其他数字作为下一次求解的备选数字。同时,要注意除法运算中存在除数和被除数的区别,并且不考虑中间运算出现负值的情况(即减法运算中被减数要大于减数)。注意做除法时除数不能为0。由于只有4个数,因此递归最多会有4层嵌套。我的解法和书中提供的解法一思想是一致的,由于C中没有运算符重载等操作,C实现要稍微负载一些。相比之下,我的程序中空间开销也比较大,每次递归调用都申请了数组,这一点可以借鉴书中提供的方法。代码如下:
书中解法二应该是一种广度优先的思想,将两个子集中的元素都进行四则运算,也有大量的冗余计算,但可以借助于之前的计算,相比解法一,它需要的空间开销要更大。
附我的C实现代码:
#include <stdio.h> #define GAME_OK 1 #define GAME_NOT_OK 0 const double dThreshold = 1E-6; typedef struct { double value; char expression[20]; }sItem; int Game24(sItem sArray[], int number); int main() { int i; int tempArray[4]; sItem sArray[4]; scanf("%d %d %d %d", &tempArray[0], &tempArray[1], &tempArray[2], &tempArray[3]); for(i = 0; i < 4; i++) { sArray[i].value = (double)tempArray[i]; sprintf(sArray[i].expression, "%d", tempArray[i]); } if(Game24(sArray, 4) == GAME_OK) printf("done.\n"); else printf("no answer.\n"); return 0; } int Game24(sItem sArray[], int number) { int i, j, k; sItem stempArray[number - 1]; if(number == 1) { if(sArray[0].value > 24.0 - dThreshold && sArray[0].value < 24.0 + dThreshold) { printf("24 = %s\n", sArray[0].expression); return GAME_OK; } return GAME_NOT_OK; } for(i = 0; i < number - 1; i++) for(j = i + 1; j < number; j++) { int kk = 0; for(k = 0; k < number; k++) if(k != i && k != j) { stempArray[kk].value = sArray[k].value; sprintf(stempArray[kk].expression, "%s", sArray[k].expression); kk++; } stempArray[number-2].value = sArray[i].value + sArray[j].value; sprintf(stempArray[number-2].expression, "(%s + %s)", sArray[i].expression, sArray[j].expression); if(Game24(stempArray, number - 1) == GAME_OK) return GAME_OK; if(sArray[i].value > sArray[j].value) { stempArray[number-2].value = sArray[i].value - sArray[j].value; sprintf(stempArray[number-2].expression, "(%s - %s)", sArray[i].expression, sArray[j].expression); } else { stempArray[number-2].value = sArray[j].value - sArray[i].value; sprintf(stempArray[number-2].expression, "(%s - %s)", sArray[j].expression, sArray[i].expression); } if(Game24(stempArray, number - 1) == GAME_OK) return GAME_OK; stempArray[number-2].value = sArray[i].value * sArray[j].value; sprintf(stempArray[number-2].expression, "%s * %s", sArray[i].expression, sArray[j].expression); if(Game24(stempArray, number - 1) == GAME_OK) return GAME_OK; if(sArray[i].value != 0.0) { stempArray[number-2].value = sArray[j].value / sArray[i].value; sprintf(stempArray[number-2].expression, "%s / %s", sArray[j].expression, sArray[i].expression); if(Game24(stempArray, number - 1) == GAME_OK) return GAME_OK; } if(sArray[j].value != 0.0) { stempArray[number-2].value = sArray[i].value / sArray[j].value; sprintf(stempArray[number-2].expression, "%s / %s", sArray[i].expression, sArray[j].expression); if(Game24(stempArray, number - 1) == GAME_OK) return GAME_OK; } } return GAME_NOT_OK; }