本文转载自hihoCoder 搜索一·24点
题意:24点是一个棋牌类益智游戏。拿一副牌,抽去大小王和JQK,剩下1到10这40张牌(以下用1代替A)。任意抽取4张牌,用加、减、乘、除(可加括号)把牌面上的数算成24。每张牌必须且只能用一次。如抽出的牌是3、8、8、9,那么算式为(9-8)×8×3=24。输入第1行是1个正整数t表示数据组数,2≤t≤100;第2..t+1行是4个正整数a,b,c,d,1≤a,b,c,d≤10。输出第1..t行每行一个字符串,第i行表示第i组能否计算出24点。若能够输出"Yes",否则输出"No"。
解析:
假设我们用⊙表示运算,⊙除了可以表示基本的"+","-","*","/"外,我们还引入两个新的运算,"反-",和"反/"。比如(a反/b)的意思是(b/a)。则对形如(c/(a+b))的形式,就可以等价的描述为((a+b)反/c)。利用这6种运算,可以将所有可能的计算过程归结为2类:(((a⊙b)⊙c)⊙d)和((a⊙b)⊙(c⊙d))。将4张牌的值,分别代入a,b,c,d,再把可能的运算符也代入就可以得到相应的计算式子,将其计算出来,再检查结果是否等于24。由于我们有4个数,所以对于a,b,c,d的对应关系有4!=24种情况。3个运算符,每个运算符可能有6种情况,那就是6^3=216。再考虑到2种不同的模式,所以一共有2*24*216=10368种情况。这并没有考虑等价的情况,比如a+b和b+a,所以实际的情况数其实是小于10368种的。不过由于对计算机而言,10368种情况数本来也不是很多,而要考虑等价反而显得比较麻烦。所以我们可以不要去考虑加法和乘法的可逆性,直接枚举所有的情况。
AC代码:
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; double a[4]; bool flag; double cnt(double a,double b,int k) { double s=0.0; switch(k) { case 0:s=a+b;break; case 1:s=a-b;break; case 2:s=a*b;break; case 3:if(b!=0)s=a/b;break; case 4:s=b-a;break; case 5:if(a!=0)s=b/a;break; } return s; } bool judge(int i,int j,int k) { if(s(cnt(cnt(a[0],a[1],i),a[2],j),a[3],k)==24) return true; if(cnt(cnt(a[0],a[1],i),cnt(a[2],a[3],k),j)==24) return true; return false; } void solve() { for(int i=0;i<6;i++) { for(int j=0;j<6;j++) { for(int k=0;k<6;k++) { if(judge(i,j,k)) { flag=true; return; } } } } } int main() { int N; cin>>N; while(N--) { flag=false; for(int i=0;i<4;i++) cin>>a[i]; sort(a,a+4); do { solve(); if(flag) break; } while(next_permutation(a,a+4)); if(flag)printf("Yes\n"); else printf("No\n"); } }