1698: 算24

题目描述:题目:算24

给出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

思路:

此题是一道dfs.

首先看到这个题目,可以先想出一种最暴力的写法,在进行优化,该井。我们 我 的第一个想法是可以枚举出数字与下一个数字的每一种情况,如:a + b | a - b | b - a | a / b | a * b ......。最后得出一个中缀表达式,再对中缀表达式进行计算,再判断是否等于24.

这种想法很容易就会被否认了,因为,他要dfs每一种情况,再对每一种情况的最后结果进行中缀计算,明显时间复杂度太大了。那有没有更好的算法呢??

我们不难想到将一个问题分为许多子问题求解,那么这道题该怎么进行这样的思路呢?我们可以先对当前序列,第一个数与其他数枚举每一种情况,再将这种情况得到的结果放入原序列再次进行如上操作即可
e.g.a b c d->e(a与b) c d->f(e与c) d->g(f与d)
最后判断是否为24即可。
(潘:代码不长也就60行)

代码:

#include <bits/stdc++.h>

using namespace std;

double eps = 1e-6;//用来double(浮点数的判断),一个无限接近0的数) 
double a[5];//存储序列 
int vis[10],n,fg = 0;//vis[]标记数组,判断此数是否被用 

void dfs(int cnt){//cnt记录目前有多少个数; 
	if(cnt == 1){//只剩最后一个数的时候,即为答案 
		if(fabs(a[1] - 24) < eps){//判断是否为24,(fabs浮点数的绝对值函数) 
			fg = 1;
			//此方案可行 
		}
		return ;
	}
	for (int i = 1;i <= 4;i++){
		for (int j = i + 1;j <= 4;j++){//两个两个枚举数字 
			if(vis[i] == 1 || vis[j] == 1){//如果次此数被用过 
				continue;//跳过 
			}
			double pre = a[i];//记录枚举的数 
			a[i] = pre + a[j];//a[1]记录的是当前情况所得的值,下面就不进行过多解释 
			vis[j] = 1;//标记此数被使用; 
			dfs(cnt - 1);
			//加法情况 
			
			a[i] = pre - a[j];
			dfs(cnt - 1);
			//减法情况(a-b) 
			
			a[i] = a[j] - pre;
			dfs(cnt - 1);
			//减法情况(b-a) 
			
			a[i] = pre * a[j];
			dfs(cnt - 1);
			//乘法情况 
			
			if(fabs(a[j]) > eps){
				a[i] = pre / a[j] ;
				dfs(cnt - 1);
			}//除法情况,a/b(!!除数不为0!!) 
			
			if(fabs(pre) > eps){
				a[i] = a[j] / pre;
				dfs(cnt - 1);
			}//除法情况,b/a(!!除数不为0!!) 
			
			a[i] = pre,vis[j] = 0;//取消标记,还原a[i] 
		}
	}
}

int main()
{
	scanf("%lf%lf%lf%lf",&a[1],&a[2],&a[3],&a[4]);
    while(a[1] != 0 || a[2] != 0 || a[3] != 0 || a[4] != 0){
    	//以0 0 0 0为结尾 
    	fg = 0;//flag便量,判断此序列是否可行 
    	dfs(4);//开始搜索 
    	if(fg){
    		cout<<"YES"<<endl;
		}
		else{
			cout<<"NO"<<endl;
		}
		scanf("%lf%lf%lf%lf",&a[1],&a[2],&a[3],&a[4]);
		//进行下一个序列的输入 
	}
    return 0;
}
posted @   XDFZ武斌  阅读(95)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示