pongo题解之24点扑克牌游戏--C++实现

24点扑克牌游戏,就是用a,b,c,d(1<=a,b,c,d<=13 ,正整数)和运算符op1,op2,op3(+、-、×、/  注意:此处/不是整除)以及括号来拼凑出24,首先考虑枚举(蛮力)a,b,c,d的排列和op1,op2,op3的排列进行一一尝试,其中只需计算下面5个式子(将运算符看作中间结点,操作数看作叶子结点的树只有5种形状,其他式子可有运算符的不同排列转换为这5种之一):

(1)        ((a op1 b) op2 c) op3 d

(2)        (a op1 (b op2 c)) op3 d

(3)        (a op1 b) op2 (c op3 d)

(4)        a op1 ((b op2 c) op3 d)

(5)        a op1 (b op2 (c op3 d))

生成运算符的排列:考虑到三个减号时不成立,可以由{+++,--,***,///}中随意选择三个的组合再生成排列,共 A4,3+ A4,2 * A3,3/A2,2 +3=63中运算符排列,这个排列的生成可以通过静态变量只在第一调运函数时生成(当然这个可以打表)。

操作数排列(johnson-trotter算法):如果将a,b,c,d的排列全部生成出来再和运算符的排列通过双层循环一一尝试的话,效率不高,所以没得到a,b,c,d的一个新排列就尝试上面5个式子在运算符排列下是否成立。

i5+4G内存下:测试所有用例(1820个)有1362个成立,时间是1.7s左右

在pongo的hero在线测试0.5s左右

部分源代码如下:

#include<iostream>
#include<vector>
#include<stack>
#include<algorithm>
#include<set>
#include<cmath>
#include<fstream>
#include<ctime>
const double pre=0.0001;
const double N=24;
std::set<std::vector<char>> resOp;//+-*/的所有排列
void combination(size_t n,std::vector<char> & v,std::vector<std::vector<char>>&res){//组合Cm,n m=v.size()
	if(n<=0||n>v.size())return;
	std::vector<size_t> pos;
	std::vector<char>r;
	for(size_t i=0;i<n;i++){
		pos.push_back(i);
		r.push_back(v[i]);
	}
	while(true){
		res.push_back(r);
		while(pos[n-1]!=v.size()-1){
			pos[n-1]++;
			r[n-1]=v[pos[n-1]];
			res.push_back(r);
		}//while
		int i=1;
		while(pos[n-1-i]==v.size()-1-i){
			if(i==n-1) return;
			i++;
		}//while
		pos[n-1-i]++;
		r[n-1-i]=v[pos[n-1-i]];
		size_t k=1;
		for(size_t j=n-i;j<=n-1;j++){
			pos[j]=pos[n-1-i]+k;
			k++;
			r[j]=v[pos[j]];
		}
	}//while (true)
}//combination()
template<typename dType >
void permutation(std::vector<dType> & v,std::set<std::vector<dType>>&resV){//由v生成排列
	if(v.size()<=0)return;
	std::vector<size_t> mid;//
	std::vector<int>direct;
	for(size_t i=0;i<v.size();i++){
		mid.push_back(i);
		direct.push_back(-1);
	}//for
	resV.insert(v);
	size_t moveEle=v.size()-1;
	size_t midP;
	size_t midMax;
	while(mid[moveEle]>0){//其实用不到	
		midP=mid[moveEle];
		mid[moveEle]=mid[moveEle+direct[midP]];
		mid[moveEle+direct[midP]]=midP;
		char midV=v[moveEle];
		v[moveEle]=v[moveEle+direct[midP]];
		v[moveEle+direct[midP]]=midV;
		resV.insert(v);
		midMax=midP;
		for(std::vector<size_t>::const_iterator cit=mid.begin();cit!=mid.end();cit++){
			if(*cit>midP){
				direct[*cit]*=-1;
				if(direct[*cit]==1&&cit+1!=mid.end()||direct[*cit]==-1&&cit!=mid.begin()){
					if(*cit>*(cit+direct[*cit])&&*cit>midMax){
						midMax=*cit;
						moveEle=cit-mid.begin();
					}//if
				}//if
			}//if
		}//for
		if(midMax==midP){
			size_t i=midP;
			for(i=midP;i>0;i--){
				std::vector<size_t>::iterator it=std::find(mid.begin(),mid.end(),i);
				if(direct[i]==1&&it+1!=mid.end()||direct[i]==-1&&it!=mid.begin()){
					if(i>*(it+direct[i])){
						moveEle=it-mid.begin();
						break;
					}//
				}//
			}//for
			if(i==0) break;
		}//if
	}//while
}//permutation
inline double comp(double a,double b,char op){
	if('+'==op)
		return a+b;
	if('-'==op)
		return a-b;
	if('*'==op)
		return a*b;
	else if('/'==op)
		return a/b;
	else 
		exit(1);
}
inline bool op1(int a,int b,int c,int d,char op1,char op2,char op3){//1
	if(std::fabs(comp(comp(comp(a,b,op1),c,op2),d,op3)-N)<=pre) return true;
	else return false;
}
inline bool op2(int a,int b,int c,int d,char op1,char op2,char op3){//2
	if(std::fabs(comp(comp(a,comp(b,c,op2),op1),d,op3)-N)<=pre) return true;
	else return false;
}
inline bool op3(int a,int b,int c,int d,char op1,char op2,char op3){//3
	if(std::fabs(comp(comp(a,b,op1),comp(c,d,op3),op2)-N)<=pre) return true;
	else return false;
}
inline bool op4(int a,int b,int c,int d,char op1,char op2,char op3){//4
	if(std::fabs(comp(a,comp(comp(b,c,op2),d,op3),op1)-N)<=pre) return true;
	else return false;
}
inline bool op5(int a,int b,int c,int d,char op1,char op2,char op3){//5
	if(std::fabs(comp(a,comp(b,comp(c,d,op3),op2),op1)-N)<=pre) return true;
	else return false;
}

void compOp(){
	std::vector<char> v;
	std::vector<std::vector<char>> res;
	v.push_back('+');
	v.push_back('+');
	v.push_back('-');
	v.push_back('-');
	v.push_back('*');
	v.push_back('*');
	v.push_back('/');
	v.push_back('/');
	v.push_back('/');
	combination(3,v,res);//C9,3
	for(std::vector<std::vector<char>>::iterator cit=res.begin();cit!=res.end();cit++)
		permutation(*cit,resOp);
}
int can24(int a,int b, int c,int d){//1=<a,b,c,d<=13
	//static bool firstTime=true; 
	int midVal =a+b+c+d;
	if(midVal==N){
		//std::cout<<a<<"+"<<b<<"+"<<c<<"+"<<d<<std::endl;
		return 1;	
	}
	midVal=a*b*c*d;
	if(midVal==N){
		//std::cout<<a<<"*"<<b<<"*"<<c<<"*"<<d<<std::endl;
		return 1;
	}
	/*if(firstTime){
		compOp();
		firstTime=false;
	}*/
	int flag=0;
	char ops [][3]={{'*','*','+'},{'*','*','-'},{'*','*','/'},{'*','+','*'},{'*','+','+'},{'*','+','-'},{'*','+','/'},{'*','-','*'},{'*','-','+'},{'*','-','-'},{'*','-','/'},{'*','/','*'},{'*','/','+'},{'*','/','-'},{'*','/','/'},{'+','*','*'},{'+','*','+'},{'+','*','-'},{'+','*','/'},{'+','+','*'},{'+','+','-'},{'+','+','/'},{'+','-','*'},{'+','-','+'},{'+','-','-'},{'+','-','/'},{'+','/','*'},{'+','/','+'},{'+','/','-'},{'+','/','/'},{'-','*','*'},{'-','*','+'},{'-','*','-'},{'-','*','/'},{'-','+','*'},{'-','+','+'},{'-','+','-'},{'-','+','/'},{'-','-','*'},{'-','-','+'},{'-','-','/'},{'-','/','*'},{'-','/','+'},{'-','/','-'},{'-','/','/'},{'/','*','*'},{'/','*','+'},{'/','*','-'},{'/','*','/'},{'/','+','*'},{'/','+','+'},{'/','+','-'},{'/','+','/'},{'/','-','*'},{'/','-','+'},{'/','-','-'},{'/','-','/'},{'/','/','*'},{'/','/','+'},{'/','/','-'},{'/','/','/'}};
	std::vector<int> vData;
	vData.push_back(a);
	vData.push_back(b);
	vData.push_back(c);
	vData.push_back(d);
	std::set<std::vector<int>> resData;
	//permutation(vData,resData);

	std::vector<size_t> mid;//
	std::vector<int>direct;
	for(size_t i=0;i<vData.size();i++){
		mid.push_back(i);
		direct.push_back(-1);
	}//for
	//resPos.push_back(mid);
	resData.insert(vData);
	std::vector<int>::iterator abcdIt=vData.begin();
	a=*abcdIt;
	abcdIt++;
	b=*abcdIt;
	abcdIt++;
	c=*abcdIt;
	abcdIt++;
	d=*abcdIt;
	for(int opi=0;opi<=60;opi++){
		if(op1(a,b,c,d,ops [opi][0],ops [opi][1],ops [opi][2])){
			///std::cout<<"method 1:"<<std::ends;
			//std::cout<<"(("<<(*citj)[0]<<(*cit)[0]<<(*citj)[1]<<")"<<(*cit)[1]<<(*citj)[2]<<")"<<(*cit)[2]<<(*citj)[3]<<std::endl;
			flag=1;
			return flag;
		}//if1
		if(op2(a,b,c,d,ops [opi][0],ops [opi][1],ops [opi][2])){
			///std::cout<<"method 2:"<<std::ends;
			//std::cout<<"("<<(*citj)[0]<<(*cit)[0]<<"("<<(*citj)[1]<<(*cit)[1]<<(*citj)[2]<<")"<<")"<<(*cit)[2]<<(*citj)[3]<<std::endl;
			flag=1;
			return flag;
		}//if2
		if(op3(a,b,c,d,ops [opi][0],ops [opi][1],ops [opi][2])){
			///std::cout<<"method 3:"<<std::ends;
			//std::cout<<"("<<(*citj)[0]<<(*cit)[0]<<(*citj)[1] <<")"<<(*cit)[1]<<"("<<(*citj)[2]<<(*cit)[2]<<(*citj)[3]<<")"<<std::endl;
			flag=1;
			return flag;
		}//if3
		if(op4(a,b,c,d,ops [opi][0],ops [opi][1],ops [opi][2])){
			///std::cout<<"method 4:"<<std::ends;
			//std::cout<<(*citj)[0]<<(*cit)[0]<<"("<<"("<<(*citj)[1]<<(*cit)[1]<<(*citj)[2]<<")"<<(*cit)[2]<<(*citj)[3]<<")"<<std::endl;
			flag=1;
			return flag;
		}//if4
		if(op5(a,b,c,d,ops [opi][0],ops [opi][1],ops [opi][2])){
			///std::cout<<"method 5:"<<std::ends;
			//std::cout<<(*citj)[0]<<(*cit)[0]<<"("<<(*citj)[1] <<(*cit)[1]<<"("<<(*citj)[2]<<(*cit)[2]<<(*citj)[3]<<")"<<")"<<std::endl;
			flag=1;
			return flag;
		}//if5
	}//for(int opi=0;opi<=60;opi++)
	size_t moveEle=vData.size()-1;
	size_t midP;
	size_t midMax;
	while(mid[moveEle]>0){
		midP=mid[moveEle];
		mid[moveEle]=mid[moveEle+direct[midP]];
		mid[moveEle+direct[midP]]=midP;
		//resPos.push_back(mid);
		char midV=vData[moveEle];
		vData[moveEle]=vData[moveEle+direct[midP]];
		vData[moveEle+direct[midP]]=midV;
		if(resData.find(vData)==resData.end())	{
			abcdIt=vData.begin();
			a=*abcdIt;
			abcdIt++;
			b=*abcdIt;
			abcdIt++;
			c=*abcdIt;
			abcdIt++;
			d=*abcdIt;
			for(int opi=0;opi<=60;opi++){
				if(op1(a,b,c,d,ops [opi][0],ops [opi][1],ops [opi][2])){
					///std::cout<<"method 1:"<<std::ends;
					//std::cout<<"(("<<(*citj)[0]<<(*cit)[0]<<(*citj)[1]<<")"<<(*cit)[1]<<(*citj)[2]<<")"<<(*cit)[2]<<(*citj)[3]<<std::endl;
					flag=1;
					return flag;
				}//if1
				if(op2(a,b,c,d,ops [opi][0],ops [opi][1],ops [opi][2])){
					///std::cout<<"method 2:"<<std::ends;
					//std::cout<<"("<<(*citj)[0]<<(*cit)[0]<<"("<<(*citj)[1]<<(*cit)[1]<<(*citj)[2]<<")"<<")"<<(*cit)[2]<<(*citj)[3]<<std::endl;
					flag=1;
					return flag;
				}//if2
				if(op3(a,b,c,d,ops [opi][0],ops [opi][1],ops [opi][2])){
					///std::cout<<"method 3:"<<std::ends;
					//std::cout<<"("<<(*citj)[0]<<(*cit)[0]<<(*citj)[1] <<")"<<(*cit)[1]<<"("<<(*citj)[2]<<(*cit)[2]<<(*citj)[3]<<")"<<std::endl;
					flag=1;
					return flag;
				}//if3
				if(op4(a,b,c,d,ops [opi][0],ops [opi][1],ops [opi][2])){
					///std::cout<<"method 4:"<<std::ends;
					//std::cout<<(*citj)[0]<<(*cit)[0]<<"("<<"("<<(*citj)[1]<<(*cit)[1]<<(*citj)[2]<<")"<<(*cit)[2]<<(*citj)[3]<<")"<<std::endl;
					flag=1;
					return flag;
				}//if4
				if(op5(a,b,c,d,ops [opi][0],ops [opi][1],ops [opi][2])){
					///std::cout<<"method 5:"<<std::ends;
					//std::cout<<(*citj)[0]<<(*cit)[0]<<"("<<(*citj)[1] <<(*cit)[1]<<"("<<(*citj)[2]<<(*cit)[2]<<(*citj)[3]<<")"<<")"<<std::endl;
					flag=1;
					return flag;
				}//if5
			}//for(int opi=0;opi<=60;opi++)
			resData.insert(vData);
		}/
		midMax=midP;
		for(std::vector<size_t>::const_iterator cit=mid.begin();cit!=mid.end();cit++){
			if(*cit>midP){
				direct[*cit]*=-1;
				if(direct[*cit]==1&&cit+1!=mid.end()||direct[*cit]==-1&&cit!=mid.begin()){
					if(*cit>*(cit+direct[*cit])&&*cit>midMax){
						midMax=*cit;
						moveEle=cit-mid.begin();
					}//if
				}//if
			}//if
		}//for
		if(midMax==midP){
			size_t i=midP;
			for(i=midP;i>0;i--){
				std::vector<size_t>::iterator it=std::find(mid.begin(),mid.end(),i);
				if(direct[i]==1&&it+1!=mid.end()||direct[i]==-1&&it!=mid.begin()){
					if(i>*(it+direct[i])){
						moveEle=it-mid.begin();
						break;
					}//
				}//
			}//for
			if(i==0) break;
		}//if
	}//while
	return flag;
}//can24()


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值