关于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”。

关于这道题目有我一个简单的看法

可将a b c d 这四个数中间的三个运算符 穷举 如 a * b + c / d

那么 只有这样的话 肯定是不够的 因为如果有括号的出现的话 他们的运算顺序肯定得发生变化
所以 在穷举三个运算符的基础上 (这三个运算符穷举次数有444种)再将所有的加括号种类列举出来 可以肯定的是 四个数字 用三个括号便可以确定其运算顺序 接下来将列举 有几种括号的摆放方式:
1.(((a b) c) d) 2.((a (b c)) d) 3.(a ((b c) d)) 4.(a(b(cd)))5.((a b) (c d))

总结以上只有五种括号摆放形式 在这种情况下 仅仅只是把 a b c d 这个顺序的所有方法列举完(如 a b d c 的排序还没有带入验证) 因此 我们还需要用到一个 全排列的函数 将其在全排列过程中 来进行判断这四个数能否组成24点

下面看代码:(小白 请谅解)

#include <iostream>
#include <cmath>
using namespace std;
char s[4]={
    
    '+','-','*','/'};
int f(double a,double b,double c,double d);
double z(double a,double b,char c);
double h[5];
int path[5];
bool used[5]={
    
    false};
void dfs(int n);
int isprime=0;
int isprime2=0;
int main()
{
    
    
	double a,b,c,d;
	cin >> a >> b >> c >> d;
	while(a!=0||b!=0||c!=0||d!=0){
    
    
		h[1]=a,h[2]=b,h[3]=c,h[4]=d;
		dfs(0); 
		if(isprime2==1){
    
    
			cout << "YES" << endl;
	}else {
    
    
		cout << "NO" << endl;
	}
	isprime=0;//每一次输入都要让它变为0
	isprime2=0;//每一次输入都要让它变为0
	for(int i=0;i<5;i++){
    
    
		used[i]=false;
	}//这个是全排列的时候用到的uesd判断
	cin >> a >> b >> c >> d;
	}
	return 0;

}
// dfs函数是全排列递归 这个应该大家都看得懂
void dfs(int n){
    
    
	if(n==3){
    
    
		for(int i=1;i<=4;i++){
    
    
			if(!used[i]){
    
    
				path[3]=i;
			}
		}
		isprime=f(h[path[0]],h[path[1]],h[path[2]],h[path[3]]);
		if(isprime==1){
    
    
			isprime2=1;
		}
	}else{
    
    
		for(int i=1;i<=4;i++){
    
    
			if(!used[i]){
    
    
				used[i]=true;
				path[n]=i;
				dfs(n+1);
				used[i]=false; 
			}
		}
	}
}
int f(double a,double b,double c,double d){
    
    
	int isprime=0;
	for(int i=0;i<4;i++){
    
    
		for(int j=0;j<4;j++){
    
    
			for(int k=0;k<4;k++){
    
    
				double t=z(z(z(a,b,s[i]),c,s[j]),d,s[k]);//下面对应着每一种括号的情况
				if(fabs(t-24)<1e-10){
    
    
					isprime=1;
				}
				t=z(z(a,z(b,c,s[j]),s[i]),d,s[k]);
				if(fabs(t-24)<1e-10){
    
    
					isprime=1;
				}
				t=z(a,z(b,z(c,d,s[k]),s[j]),s[i]);
				if(fabs(t-24)<1e-10){
    
    
					isprime=1;
				}
				t=z(a,z(z(b,c,s[j]),d,s[k]),s[i]);
				if(fabs(t-24)<1e-10){
    
    
				
					isprime=1;
					
			
				}
				t=z(z(a,b,s[i]),z(c,d,s[k]),s[j]);
				if(fabs(t-24)<1e-10){
    
    
				
					isprime=1;
		
				}
			}
		}
	}
	return isprime;
	
}
double z(double a,double b,char c){
    
    
	double k;
	//我个人感觉其实这里还应该写一个当 b==0 c=='/'时候要做一些措施,但是能过测试我就没有加了。
	switch (c){
    
    
		case '+' : k=a+b;break;
		case '-' : k=a-b;break;
		case '*' : k=a*b;break;
		case '/' : k=a/b;break;
	}
	return k;
}

第一次写 希望体谅 可能有的部分写的不是很好 或者写了些冗余的代码 以后会慢慢改进的 谢谢!!

猜你喜欢

转载自blog.csdn.net/weixin_52806898/article/details/115186794