编写目的
记录一下自己刷OJ题时遇到一个有意思的,不那么复杂的问题:24点问题。
题目描述
速算24点相信绝大多数人都玩过。就是随机给你四张牌,包括 A(1),2,3,4,5,6,7,8,9,10,J(11),Q(12),K(13)。要求只用’+’,’-’,’*’,’/'运算符以及括号改变运算 顺序,使得最终运算结果为24(每个数必须且仅能用一次)。游戏很简单,但遇到无解的情况往往让人很郁闷。你的任务就是针对每一组随机产生的四张牌,判断 是否有解。我们另外规定,整个计算过程中都不能出现小数。
输入
输入数据占一行,给定四张牌。
输出
如果有解则输出"Y",无解则输出"N"。
样例输入
A 2 3 6
样例输出
Y
解决方法
问题分析: 不管怎么运算,最终结果肯定是回答 A [ + - * / ] B == 24
这个问题。这里面的A 和 B不一定是一个数,也可以是一个表达式,比如说 A = (1+5)
B = (1+3)
,所以A * B == 24
成立。
所以对于 a b c d 四个数,我们不妨平分成两组,A 和 B两组,然后尝试所有方法,看看能不能凑出这个数。
代码如下:
#include <iostream>
using namespace std;
/**
* 把 a 和 b 加减乘除 所有可能的结果都写在ary数组中
* 需要注意 分母为0这种情况
*/
void results(int a,int b,int ary[]) {
// +
ary[0] = a+b;
// -
ary[1] = a > b ? a-b : b-a;
// *
ary[2] = a*b;
// 如果不能整除的话,放弃这种方案,-999 即表示放弃这种方案
if(a > b && b!=0 && a%b == 0 ) {
ary[3] = a/b;
} else if(b > a && a!=0 && b%a == 0) {
ary[3] = b/a;
} else {
ary[3] = -999;
}
}
/**
* 计算出两个数组中数据组合运行的所有可能出现的结果
* 如果运算结果可以包含24,则返回true,否则返回false
*/
bool judgeOk(int ary1[],int ary2[]) {
int i,t,j;
int ary[4];
for(i=0; i<4; i++) {
for(t=0; t<4; t++) {
results(ary1[i],ary2[t],ary);
for(j=0; j<4; j++) {
if(ary[j] == 24) {
return true;
}
}
}
}
return false;
}
/**
* 把字母与数字一一对应
*/
int toInt(string str) {
if(str == "A") {
return 1;
}
if(str == "J") {
return 11;
}
if(str == "Q") {
return 12;
}
if(str == "K") {
return 13;
}
if(str == "10") {
return 10;
}
return str[0]-'0';
}
// 欢迎关注 https://blog.csdn.net/smileyan9
int main()
{
// 输入以及各式转换
string str1,str2,str3,str4;
int a,b,c,d;
cin>>str1>>str2>>str3>>str4;
a = toInt(str1);
b = toInt(str2);
c = toInt(str3);
d = toInt(str4);
int ary1[4];
int ary2[4];
bool flag = false;
results(a,b,ary1);
results(c,d,ary2);
// 如果(a,b) 与 (c,d)组合就可以凑成24点
if(judgeOk(ary1,ary2) == true) {
flag = true;
} else {
// 如果不能,则尝试(a,c)与(b,d)组合
results(a,c,ary1);
results(b,d,ary2);
if(judgeOk(ary1,ary2) == true) {
flag = true;
} else {
// 如果不能,则尝试(a,d)与(b,c)组合
results(a,d,ary1);
results(b,c,ary2);
if(judgeOk(ary1,ary2) == true) {
flag = true;
}
}
}
if(flag == true) {
cout<<"Y"<<endl;
} else {
cout<<"N"<<endl;
}
return 0;
}
总结
因为四个数(或者多个数)的运算最终步骤肯定是转换成两个数的运算,比如1x2x3x4最终就是 6x4,所有题目其实就是研究 24 == A [±*/] B 能不能成功,然后我们把A拆分成两个数的“自由运算”,B也拆分成两个数的“自由运算”,然后就可以凑出结果了。
当然,不一定运算结果是24,也不一定是4个数,这种简单运算最终都是转换成两个数进行运算的。
扩展(不妨思考思考)
问题1:如果答案有解,怎么输出答案的解?
问题2:如果把题目中24改成其他数,怎么解决问题?
问题3:如果不是4个数的运算,而是5个数,或者更多个数的运算,怎么解决问题?
Smileyan
2019年9月15日 21:37