1、 问题描述
24点游戏是经典的纸牌益智游戏。
常见游戏规则:
从扑克中每次取出4张牌。使用加减乘除,第一个能得出24者为赢。(其中,J代表11,Q代表12,K代表13,A代表1),按照要求编程解决24点游戏。
基本要求: 随机生成4个代表扑克牌牌面的数字字母,程序自动列出所有可能算出24的表达式。
2、 算法构造
应用穷举法搜索整个解集,筛选出符合题目要求的全部解。关键的问题是如何确定该题的解集。假设输入的4个整数为A、B、C、D,如果不考虑括号优先级的情况,仅用四则运算符将它们连接,例如:A+BC/D,利用数学排列组合求得共有64种表达式情形。如果考虑加括号的情况,暂不考虑运算符,共有以下5种情形:
(1)((A□B)□C)□D
(2)(A□(B□C))□D
(3)A□(B□(C□D))
(4)A□((B□C)□D)
(5)(A□B)□(C□D)
其中□代表(±/)任意的运算符。将上面两种情况综合起来考虑,每输入4个整数,其构成的解集为64*5=320种表达式。也就是说,每输入4个整数,无论以什么方式或优先级进行四则运算,其结果都会在这320种答案之中。我们就是要在这320种表达式中寻找出计算结果为24的表达式。
3、 源程序
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
char symbol[4]={'+','-','*','/'}; //定义四个符号的数组
float cal(float x,float y,int n) //两个数之间的四种运算情况
{
switch(n)
{
case 1:return x+y;
case 2:return x-y;
case 3:return x*y;
case 4:return x/y;
}
}
//对应表达式类型:((A□B)□C)□D
float calculate1(float i,float j,float k,float t,int n1,int n2,int n3)
{
float r1,r2,r3;
r1=cal(i,j,n1);
r2=cal(r1,k,n2);
r3=cal(r2,t,n3);
return r3;
}
//对应表达式类型:(A□(B□C))□D
float calculate2(float i,float j,float k,float t,int n1,int n2,int n3)
{
float r1,r2,r3;
r1=cal(j,k,n1);
r2=cal(i,r1,n2);
r3=cal(r2,t,n3);
return r3;
}
//对应表达式类型:A□(B□(C□D))
float calculate3(float i,float j,float k,float t,int n1,int n2,int n3)
{
float r1,r2,r3;
r1=cal(k,t,n1);
r2=cal(j,r1,n2);
r3=cal(i,r2,n3);
return r3;
}
//对应表达式类型:A□((B□C)□D)
float calculate4(float i,float j,float k,float t,int n1,int n2,int n3)
{
float r1,r2,r3;
r1=cal(j,k,n1);
r2=cal(r1,t,n2);
r3=cal(i,r2,n3);
return r3;
}
//对应表达式类型:(A□B)□(C□D)
float calculate5(float i,float j,float k,float t,int n1,int n2,int n3)
{
float r1,r2,r3;
r1=cal(i,j,n1);
r2=cal(k,t,n2);
r3=cal(r1,r2,n3);
return r3;
}
int get24(int i,int j,int k,int t)
{
int n1,n2,n3;
int flag=0;
for(n1=0;n1<4;n1++) //三重循环共64种情况
for(n2=0;n2<4;n2++)
for(n3=0;n3<4;n3++)
{ //以下有五种加括号的方法,总共有64*5=320种情况
if(calculate1(i,j,k,t,n1,n2,n3)==24)
{
printf("((%d%c%d)%c%d)%c%d=24\n",i,symbol[n1],j,symbol[n2],k,symbol[n3],t);
flag = 1;
}
if(calculate2(i,j,k,t,n1,n2,n3)==24)
{
printf("(%d%c(%d%c%d))%c%d=24\n",i,symbol[n1],j,symbol[n2],k,symbol[n3],t);
flag = 1;
}
if(calculate3(i,j,k,t,n1,n2,n3)==24)
{
printf("%d%c(%d%c(%d%c%d))=24\n",i,symbol[n1],j,symbol[n2],k,symbol[n3],t);
flag = 1;
}
if(calculate4(i,j,k,t,n1,n2,n3)==24)
{
printf("%d%c((%d%c%d)%c%d)=24\n",i,symbol[n1],j,symbol[n2],k,symbol[n3],t);
flag = 1;
}
if(calculate5(i,j,k,t,n1,n2,n3)==24)
{
printf("(%d%c%d)%c(%d%c%d)=24\n",i,symbol[n1],j,symbol[n2],k,symbol[n3],t);
flag = 1;
}
}
return flag;
}
int main()
{
srand((int)time(0));
int i,j,k,t;
int a[4];
for(i=0;i<4;i++) //随机产生四个1~13之间的整数
{
a[i]=1+(int)(rand()%13);
}
for(i=0;i<4;i++)
{
printf("%3d",a[i]);
}
printf("\n");
i=a[0];
j=a[1];
k=a[2];
t=a[3];
if(get24(i,j,k,t));
else printf("这四个数不能得到24\n");
getchar();
return 0;
}
4、程序测试及调试结果
程序测试结果截图
程序调试截图
5、总结体会
此次课程设计题目是24点问题,了解题目之后就是整理思路进行算法设计,我采用的是穷举法,在算法设计中的难点在于考虑所有可能的结果,容易遗漏或考虑不全面。接下来是程序的编写和调试,编写过程比较顺利,在第一次运行时我没有设置好随机数字的范围,即随机数中出现了0,我修改了程序,使得随机数范围在1~13之间。至此程序已经完成,功能符合题目要求,但是穷举法比较费时费力,对于24点问题更简便的方法是采用递归算法,下次可以尝试用其他方法解决24点问题。
通过这次学习,我学习到了很多,这个程序难度不是特别大,但是算法比较繁琐,考虑需要细心才行。通过此次程序设计,也让我把平时学习的理论知识运用在了实际问题上,让我对理论更加熟悉。