openjudge_2.5基本算法之搜索_1789:算24

文章讲述了如何使用C++编程实现24点游戏问题,通过递归和回溯策略,考虑加减乘除和括号的使用,以求解给定数字组合是否能得到24的表达式。
摘要由CSDN通过智能技术生成

题目

1789:算24
总时间限制: 3000ms 内存限制: 65536kB
描述
给出4个小于10个正整数,你可以使用加减乘除4种运算以及括号把这4个数连接起来得到一个表达式。现在的问题是,是否存在一种方式使得得到的表达式的结果等于24。

这里加减乘除以及括号的运算结果和运算的优先级跟我们平常的定义一致(这里的除法定义是实数除法)。

比如,对于5,5,5,1,我们知道5 * (5 – 1 / 5) = 24,因此可以得到24。又比如,对于1,1,4,2,我们怎么都不能得到24。
输入
输入数据包括多行,每行给出一组测试数据,包括4个小于10个正整数。最后一组测试数据中包括4个0,表示输入的结束,这组数据不用处理。
输出
对于每一组测试数据,输出一行,如果可以得到24,输出“YES”;否则,输出“NO”。
样例输入
5 5 5 1
1 1 4 2
0 0 0 0
样例输出
YES
NO

理解

  • 深搜,回溯,加了不行就撤销,改成-*/。按题意大概
  • 可以使用加减乘除4种运算以及括号——坑,怎能理解到加减乘除不限。四个运算符,必须只用三个,所以得去掉一个。所以说不是非要都要用,也不是非要每个用一次。
  • 括号可以有一个,也可以有两个。1 7 4 9——(9-1)(7-4)=83=24,7 3 1 5——(7-3)(5+1)=46=24。难点在括号。数子存在四个位置,标记一个就算用过了,没有标记就可以存运算结果。已经是结果了,当然是在括号里。没有标记的可以有两个。

代码

#include <bits/stdc++.h>
using namespace std;
double d[4];//四个整数,因为实数除法,干脆小数
bool ans,//最后结果,
k[4];//那个已经用过,还有结果存在数组哪个位置中
bool in(){//只有4个0时,输入结束
bool k=0;
for(int i=0;i<4;i++){
cin>>d[i];k=k||d[i];
}
return k;
}
void go(int x){
if(x3){//四个数三次运算,0,1,2。x3运算完结
for(int i=0;i<4;i++)
if(!k[i])//运算结果存在唯一没有标记的位置中
if(d[i]>23.9&&d[i]<24.1){//四个整数,实数除法,结果等于24,没说23.9到24.1,坑
ans=1;
}
return;
}
if(ans)return;//有一组正确答案就不用再找了,终结递归,不再扩散
double a,b;//第三变量,便于回溯
for(int i=0;i<4;i++)//遍历所有数
if(!k[i])//只有没有标记过的可以存结果。也可以说是已经优先计算的括号内结果。最多两个括号。(7-3)(5+1)=46=24
for(int j=i+1;j<4;j++)//当前数和剩下的数计算
if(!k[j]){//没标记过,参与计算
a=d[i],b=d[j];
k[j]=1;//标记用了
d[i]=a+b;go(x+1);//存在没标记的i位置。
d[i]=a-b;go(x+1);//存差
d[i]=b-a;go(x+1);//a有可能是运算结果,b也可能是,如(7-3)(5+1)
d[i]=a
b;go(x+1);
d[i]=a/b;go(x+1);
d[i]=b/a;go(x+1);
d[i]=a;//回溯,恢复该步以前状态
k[j]=0;//取消标记
}
}
int main(){
//freopen(“data.cpp”,“r”,stdin);
while(in()){
ans=0;
go(0);
if(ans)cout<<“YES\n”; else cout<<“NO\n”;
}
return 0;
}

小结

  • 递归回溯有意思
  • 用ans判断,杜绝其它方向的深搜
  • 两个括号的设定的确闻所未闻,很强大。用某没标记过数组存计算结果。厉害
  • 手动多个方向递归,而不是循环,也是厉害。
  • 19
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值