Time Limit:1000ms Memory Limit: 65535KB
在Jason生活的星球上,算术学期末总是考同样的题目:抽四张扑克牌,在1秒内通过四则运算让其结果为24。
但是Jason的算术太拙了,总是没办法在1秒内得到正确答案。期末考试就快要到了,但正直的Jason不想靠命运力神抽4张6来通过考试。
你能为Jason设计一个24点的算法,好让他不挂科吗?
输入:
给定一个提示输入行,让监考老师输入四个正整数 (均小于INT_MAX)
输出:
如果能够算出24,打印一个由输入数字组成的结果为24的四则运算算式,用括号表明优先级
否则输出一个"You WIN!"
例子:
Input
请输入四张牌的点数:
6 6 6 6
Output
((6+6)+6)+6=24
...
(以上纯属瞎说)
四个数字的所有排列组合有4! == 24种,三个运算符的运算次序有3! == 6种(实际上只有5种,因为1->3->2 和3->1->2 得到的结果是一样的),这个规模完全可以用穷举来做
可以考虑用穷举+深度优先算法来解决这个问题。
首先要能够将四个数字的全部排列组合,由于每个对于(n+1)个数的排列组合其实由第(n+1)个数与前n个数的全排列中每个数位分别交换,加上处于第(n+1)个数位上的情况得到,这位穷举排列提供了思路,也就是输入两个参数a和b,循环地将card[a]和a~b之间每个数交换,交换后对a后面作全排列。
在每次排列列举结束时,a就大于b,这时将这一排列进行完全四则运算,如果得到结果就打印出来。
#include
#include
using namespace std;
int card[4];
bool DFS(int,int);
bool full_cal();
double arith_cal(double, double, int);
char oprt(int);
int main()
{
do
{
printf("请输入四张牌的点数:\n");
scanf("%d %d %d %d", card, card + 1, card + 2, card + 3);
if (!DFS(0, 3))
printf("You WIN!\n");
} while (getchar() != 'q');
return 0;
}
bool DFS(int a, int b)
{
if (a > b) //如果左标a大于b,说明上一次交换已经达到了b与b交换,深度到底,这时可以将此排列作完全四则运算
{
if (full_cal())
return 1;
}
else
{
for (int i = a; i <= b; i++)
{
swap(card[a], card[i]); //交换第i个与第a个数
if (DFS(a + 1, b)) //运算a后面几个数
return 1;
swap(card[a], card[i]); //换回来,为之后的运算提供基础
}
}
return 0;
}
bool full_cal()
{
double a = (double)card[0]; //考虑可能的分数运算 用double存储
double b = (double)card[1];
double c = (double)card[2];
double d = (double)card[3];
int i, j, k, l; //i控制运算顺序,j、k、l控制运算符
for (i = 0; i<5; i++)
for (j = 0; j<4; j++)
for (k = 0; k<4; k++)
for (l = 0; l<4; l++)
{
switch (i)
{
case 0:
if (arith_cal(arith_cal(arith_cal(a, b, j), c, k), d, l) == 24)
{
printf("((%d%c%d)%c%d)%c%d=24\n", card[0], oprt(j), card[1], oprt(k), card[2], oprt(l), card[3]);
return 1;
}
case 1:
if (arith_cal(arith_cal(a, b, j), arith_cal(c, d, l), k) == 24)
{
printf("(%d%c%d)%c(%d%c%d)=24\n", card[0], oprt(j), card[1], oprt(k), card[2], oprt(l), card[3]);
return 1;
}
case 2:
if (arith_cal(arith_cal(a, arith_cal(b, c, k), j), d, l) == 24)
{
printf("(%d%c(%d%c%d))%c%d=24\n", card[0], oprt(j), card[1], oprt(k), card[2], oprt(l), card[3]);
return 1;
}
case 3:
if (arith_cal(a, arith_cal(arith_cal(b, c, k), d, l), j) == 24)
{
printf("%d%c((%d%c%d)%c%d)=24\n", card[0], oprt(j), card[1], oprt(k), card[2], oprt(l), card[3]);
return 1;
}
case 4:
if (arith_cal(a, arith_cal(b, arith_cal(c, d, l), k), j) == 24)
{
printf("%d%c(%d%c%(%d%c%d))=24\n", card[0], oprt(j), card[1], oprt(k), card[2], oprt(l), card[3]);
return 1;
}
}
}
return 0;
}
double arith_cal(double a, double b, int i)
{
switch (i)
{
case 0:
return a + b;
case 1:
return a - b;
case 2:
return a*b;
case 3:
if (b == 0) //除数为0时返回一个-1,让结果肯定不等于24
return -1;
else
return a / b;
}
}
char oprt(int p)
{
switch (p)
{
case 0:
return '+';
case 1:
return '-';
case 2:
return '*';
case 3:
return '/';
}
}