分析:
半年前看到过这道题,当时是用了一段很暴力的代码骗过去的;今年学习数据结构时在深搜板块中发现这道题,这才醒悟它原来是个搜索题——套用了深搜的模板,带着许多投机取巧的要素和笨办法,总算是写好了。
这道题作为搜索题有它的独特之处——先不说减法和除法的方向性,光是计算结果又要插回去继续参与接下来的搜索这一点就令人心烦。为了解决这个问题,我设置了一个数组x[4],用于存储待处理的a[]中的数字:一开始时将四个数字读到a[]中,x[4]初始化为{0,1,2,3},然后深搜传递的参数i是针对x[]的,表示a[]中以x[0]~x[i]之间存储的内容为下标的数字是待使用的(包括尚未使用的初始数据和尚未使用的计算结果)。然后深搜的目标条件就是i==0,此时a[x[0]]中存储的数据就是根据之前的搜索路线得到的结果,把它和24比较,相等就退出搜索;不相等就回溯,继续搜索。
在搜索的过程中,我使用了j和k两个指针指向x[0]~x[i]中的任意两个不同的数字,分别将它们进行加减乘除四种运算(这里我偷了个懒,因为j和k两个指针是任意指的,所以就不用考虑减法和除法的方向性了。)运算后将结果存在a[x[j]]中(在这之前先保存下a[x[j]]的值,方面后面回溯)。这样,a[x[j]]中存放着尚未使用的数据,a[x[k]]中存放着已使用过的数据,a[x[i]]中的数据尚未使用(k==i时也不影响程序),而k≤i,所以我交换了x[k]和x[i]的值,保证a[]中以x[0]到x[i-1]中存放的值为下标的数据都是尚待使用的。然后将i-1作为参数传入下一层搜索。搜索回来后再交换回x[i]和x[k],将一开始存放的a[x[j]]的值再放回去,将一切恢复原状,进行下一轮搜索。
具体代码如下:
#include<stdio.h>
using namespace std;
double a[4]={0};//用于存储计算过程中的数字
int flag;//能否凑出24的标记
int x[4]={0,1,2,3}; //x[i]中存储的数为a[]中待使用的数
//使用时为for(int i=0;i<dfs的传递参数;i++)a[x[i]];
double abs(double a);
void dfs(int i);;//表示以x[0]~x[i]中的数字为下标的a[]的数字尚未用过
int main(){
while(true){
flag=0;
for(int i=0;i<4;i++)
scanf("%lf",&a[i]);
if(!a[0] && !a[1] && !a[2] && !a[3]) return 0;
dfs(3);//表示以x[0]~x[3]中的数字为下标的a[](也就是全部)的数字尚未用过
printf("%s\n",flag?"YES":"NO");
}
}
void dfs(int i){
if(i==0){//表示此时只有a[x[0]]中的数字尚未用过——这是计算的最后结果
if(abs(a[x[0]]-24)<0.0001)
flag=1;
return;
}
for(int j=0;j<=i;j++)
for(int k=0;k<=i;k++){
if(j==k)continue; //j和k是两个指针,指向a[]中两个不同的数字,用于计算
for(int l=1;l<=4;l++){//一共加减乘除四种情况,本来减和除有方向的区别,但因为j和k的两个指针是取了所有情况的,所以就不用了
double tmp=a[x[j]];//a[x[j]]和a[x[k]]的运算结果将存储在a[x[j]]中进行之后的搜索,为了回溯,这里先保存一下a[x[j]]的值
switch(l){
case 1:a[x[j]]=a[x[j]]+a[x[k]]; break;
case 2:a[x[j]]=a[x[j]]-a[x[k]]; break;
case 3:a[x[j]]=a[x[j]]*a[x[k]]; break;
case 4:a[x[j]]=a[x[j]]/a[x[k]]; break;
// case 5:a[x[j]]=a[x[k]]-a[x[j]]; break;
// case 6:a[x[j]]=a[x[k]]-a[x[j]]; break;
}
{int tmpn=x[k];
x[k]=x[i];
x[i]=tmpn;}//a[x[k]]在上面已经用过,不再需要,而a[x[i]]尚未用到(i==k时同样),故交换x[k]和x[i],保证在x[i]以前的所有x[]对应的a[]都是尚待使用的
dfs(i-1);
{int tmpn=x[k];
x[k]=x[i];
x[i]=tmpn;}//交换回来,恢复原状
a[x[j]]=tmp;//恢复原状,开始下一轮搜索
if(flag)
return;
}
}
return;
}
double abs(double a){
if(a>0)return a;
return -a;
}