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()