思路:算24点可以归结为 A B C D=24(中间添加运算符以及括号)。一共4个数,对其进行全排列4!=24种,然后对于每一种排列添加运算符和括号。判断结果是否等于24.
这种题目是思路很简单,但是实践起来却很考研编程技巧以及思维上的取巧。
首先要引入一个以前从未接触过的函数:next_permutation。(全排列函数,用之前一定要sort一下,因为它只输出当前这种排列后的排列)
范例:
第一个输出结果第一列都为1,下面分别是1 2 3中缺失的。具体可以百度一下。
然后就是小技巧了:对于+和*来说它们满足交换律,但对于-和/来说则不满足,因此,这里定义一个(~/)和(~-)的概念,这样就有a-b=b~-a,于是乎所有操作都满足交换律。即所有的括号添加就只有这两种情况:(((a#b)#c)#d)和(a#b)#(c#d)这里的"#"表示任意运算。其他的添加括号的方式都可以通过交换律转化成这两种。
具体参考:http://blog.csdn.net/octopusflying/article/details/51428337。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int n,a[4];
double eps=1e-6;///因为用到double所以注意精度的设置
double cal(double a,double b,int op){///注意传值传double
if(op==0)
return (a+b)*1.0;
else if(op==1)
return (a-b)*1.0;
else if(op==2)
return (b-a)*1.0;
else if(op==3)
return a*b*1.0;
else if(op==4&&b!=0)
return (1.0*a)/b;
else if(op==5&&a!=0)
return (1.0*b)/a;
}
void solve(){
do{
for(int i=0;i<6;i++)
for(int j=0;j<6;j++)
for(int k=0;k<6;k++){
if(abs(cal(cal(cal(a[0],a[1],i),a[2],j),a[3],k)-24)<eps)///((a$b) $c)$d
{printf("YES\n");return;}
if(abs(cal(cal(a[0],a[1],i),cal(a[2],a[3],k),j)-24)<eps)///(a$b)$(c$d)
{printf("YES\n");return;}
}
}while(next_permutation(a,a+4));
printf("NO\n");
return;
}
int main(){
while(scanf("%d",&n)!=EOF){
for(int i=0;i<n;i++){
for(int j=0;j<4;j++)
scanf("%d",&a[j]);
sort(a,a+4);
solve();
}
}
return 0;
}