四个数的运算结果,可以看成三个数的运算结果与一个数的运算结果
三个数的运算结果,可以看成两个数的运算结果与一个数的运算结果
两个数的运算结果,可以看成一个数的运算结果与一个数的运算结果
我们A,B,B,D表示四个数,用X表示某种运算关系,可以得到如下:
X(ABCD)= X(A X(BCD))
X(A X(BCD)) = X(A X(X(B X(CD))))
X(A X(X(B X(CD))))= X(A X(X(B X(X(CXD)))))
以上可知:任意四个数的运算结果,可以转化为前两个数的运算结果 与 第三个数的运算结果 与 第四个数的运算结果。
值得注意的是,如果是1 2 3 4 这四个数,其实同时包含了 -1 -2 -3 -4 这四个数。
举个例子:
5x(5-1/5)= -1/5的结果 + 5 的结果 x 5的结果 = (-1/5+5)x5
因此我们可以设计程序,从左至右,每次计算两个枚举数的值,进而得出最终结果。
这里使用深度遍历的方式枚举所有的可能,ABCD四个数,在1234个位置上都要出现。
dfs(int n,double ans int *a)的n表示当前结算第几个数与ans的运算结果,ans记录上一次运算的结果,数组a中存储着ABCD四个数。
最开始,我们默认第一个计算的结果ans为数组中的第一个数,即ans = a[0],注意这里的a[0]每次计算之后需要调整,使ABCD四个数都在a[0]中出现过。
0位置的数用完之后,与之计算的下一个数自然就是1位置的数了,所以n初值为1。
使用0123这四个数映射+-x/四种运算。
注意前面提到的,每个数都可以变为负数。
#include<stdio.h>
int flag = 0;
void dfs(int n,double ans,int *a){
if(n==4){
if(ans == 24){
flag = 1;//flag=1输出Yes
}
}
if(n<4){
for(int i=n;i<4;i++)
for(int w=0;w<4;w++){
if(w==0){
dfs(n+1,ans+a[n],a);
dfs(n+1,-(ans+a[n]),a);
}
if(w==1){
dfs(n+1,ans-a[n],a);
dfs(n+1,-(ans-a[n]),a);
}
if(w==2){
dfs(n+1,ans*a[n],a);
dfs(n+1,-ans*a[n],a);
}
if(w==3){
dfs(n+1,ans/double(a[n]),a);
dfs(n+1,-ans/double(a[n]),a);
}
}
}
}
int main(){
int point[2];
while(true){
int a[4];
for(int i=0;i<4;i++){
scanf("%d",a+i);
}
if(a[0]==0&&a[1]==0&&a[2]==0&&a[3]==0)
break;
for(int i=0;i<4;i++){
//四个数都有机会充当第一个数进行计算
int t = a[0];
a[0] = a[i];
a[i] = t;
dfs(1,a[0],a);
//别忘了还原,下次还要交换
t = a[0];
a[0] = a[i];
a[i] = t;
}
if(flag)
printf("YES\n");
else
printf("NO\n");
flag = 0;
}
return 0;
}
网友评论