[24点计算器][C++版本]无聊拿去玩
Posted Gster
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[24点计算器][C++版本]无聊拿去玩相关的知识,希望对你有一定的参考价值。
程序用法:
输入n,tar,lim;分别表示n个数,目标答案,最多计算lim个解(0表示输出所有解)
然后输入n个数字
例: 4 24 3
1 2 3 4
表示4个数字1,2,3,4要算出24的前三个解
一般6个数找所有答案开O2需要一分半吧。。
思路(当然是爆枚咯。。。):
由于中缀表达式枚举括号比较麻烦,所以用后缀表达式枚举运算符,最后再把后缀转成中缀输出即可。
但这样还枚举不全,需要枚举数字的全排列再把运算符填进去。
这样虽然可以枚举所有情况,但是因为交换律的存在大量重复出现(比如2*3*4 3*2*4...)所以要去重。。
由于本人能力有限,,所以用了奇怪的方法,,不过效果还不错,方法如下。
随机生成若干个(程序里是4个)数组,和原数组匹配,然后用同样的运算符计算各个数组,把答案打包存进map有重复不输出即可
例:
比如当前枚举的运算方法是(a+b)/c*d
原数组:
w x y z ==>(w+x)/y*z
随机数组:
a[0][0] a[0][1] a[0][2] a[0][3] ==>(a[0][0]+a[0][1])/a[0][2]*a[0][3]=A
a[1][0] a[1][1] a[1][2] a[1][3] ==>(a[1][0]+a[1][1])/a[1][2]*a[1][3]=B
a[2][0] a[2][1] a[2][2] a[2][3] ==>(a[2][0]+a[2][1])/a[2][2]*a[2][3]=C
......
把{A,B,C,....}放到map里
当枚举到(b+a)/c*d的时候发现
x w y z ==>(x+w)/y*z
a[0][1] a[0][0] a[0][2] a[0][3] ==>(a[0][1]+a[0][0])/a[0][2]*a[0][3]=D
a[1][1] a[1][0] a[1][2] a[1][3] ==>(a[1][1]+a[1][0])/a[1][2]*a[1][3]=E
a[2][1] a[2][0] a[2][2] a[2][3] ==>(a[2][1]+a[2][0])/a[2][2]*a[2][3]=F
此时{A,B,C,...}=={D,E,F,...}说明(a+b)/c*d和(b+a)/c*d是同样的表达式,那么不输出即可。
代码如下(后缀转中缀不会写啊。。捂脸。网上扒了一篇。。):
#include <bits/stdc++.h> using namespace std; const int base=10; int n,a[100],vec[100],tar,trw=1,Cnt; int test[100][4],testb[100][4]; bool visited[100]; //==============EXCHANGE============== namespace EXCHANGE { int JudgePriority(char c); int Length; class StringNode { private: string STring; int priority; public: StringNode() { priority = 10; } StringNode(char Char1) { STring = Char1; priority = 4; } StringNode(string ExpressionString, int Priority1) { STring = ExpressionString; priority = Priority1; } friend StringNode Compose(StringNode &SN1, char Operator, StringNode &SN2) { AutoAddBrackets(SN1, Operator, SN2); return StringNode(SN1.STring + Operator + SN2.STring, JudgePriority(Operator)); } friend StringNode Compose(StringNode &SN1, char Operator) { AutoAddBrackets(SN1); SN1.STring += Operator; return StringNode(SN1.STring, 3); } friend void AutoAddBrackets(StringNode &SN1, char Operator, StringNode &SN2) { if (SN1.priority >= JudgePriority(Operator) && JudgePriority(Operator) >= SN2.priority) { SN2.AddBrackets(); return; } else if (SN1.priority == 1 && (Operator==‘*‘|| Operator == ‘/‘) && SN2.priority >= 3) { SN1.AddBrackets(); return; } else if (SN1.priority == 1 && (Operator == ‘*‘ || Operator == ‘/‘) && SN2.priority <= 2) { SN1.AddBrackets(); SN2.AddBrackets(); return; } else return; } friend void AutoAddBrackets(StringNode &SN1) { if (SN1.priority<3 ) { SN1.AddBrackets(); } } void AddBrackets() { STring = STring.insert(0,1,‘(‘) + ")"; priority = 4; } void PrintString() { cout << STring; } string ReturnString() { return STring; } }; class Stack { private: StringNode *Buffer; int top; public: Stack(int Len) { Buffer = new StringNode[Len]; top = 0; } void push(StringNode val) { Buffer[top++] = val; } StringNode pop() { top--; return Buffer[top]; } void PrintStack() { Buffer[0].PrintString(); } string ReturnString() { return Buffer[0].ReturnString(); } }; bool IsCharacter(char c) { return c >= ‘a‘&&c <= ‘z‘; } bool IsBiOperator(char c) { return c==‘+‘||c==‘*‘||c==‘/‘||c==‘-‘; } bool IsSingleOperator(char c) { return c == ‘!‘; } int JudgePriority(char c) { if (c == ‘+‘ || c == ‘-‘) return 1; else if (c == ‘*‘ || c == ‘/‘) return 2; else if (c == ‘!‘) return 3; else return 10; } string work(string Str) { int c = 0; Length = Str.size(); Stack StackObject(Length); while (c < (int)Str.size()) { if (IsCharacter(Str.at(c))) { StackObject.push(StringNode(Str.at(c))); } else if (IsBiOperator(Str.at(c))) { StringNode TempSN1 = StackObject.pop(); StringNode TempSN2 = StackObject.pop(); StackObject.push (Compose(TempSN2, Str.at(c), TempSN1)); } else if (IsSingleOperator(Str.at(c))) { StringNode TempSN = StackObject.pop(); StackObject.push (Compose(TempSN,Str.at(c))); } c++; } return StackObject.ReturnString(); } } //=============EXCHANGE==END============ struct T { double aa,bb,cc,dd; bool operator<(const T temp)const { if(fabs(aa-temp.aa)>1e-3) return aa<temp.aa; if(fabs(bb-temp.bb)>1e-3) return bb<temp.bb; if(fabs(cc-temp.cc)>1e-3) return cc<temp.cc; if(fabs(dd-temp.dd)>1e-3) return dd<temp.dd; return false; } }; vector<int> op[100]; map<T,bool> Map; void Init_random_list() { srand(time(0)); for(int j=0;j<4;++j) for(int i=0;i<n;++i) test[i][j]=rand()%(base*10); for(int i=0;i<n;++i) for(int j=i+1;j<n;++j) if(a[i]==a[j]) for(int k=0;k<4;++k) test[j][k]=test[i][k]; return ; } double C() { stack<double> S; stack<double> r[4]; for(int i=0;i<n;++i) { S.push(vec[i]); for(int j=0;j<(int)op[i].size();++j) { double t1=S.top(); S.pop(); double t2=S.top(); S.pop(); if(op[i][j]==0) S.push(t2+t1); if(op[i][j]==1) S.push(t2-t1); if(op[i][j]==2) S.push(t2*t1); if(op[i][j]==3) S.push(t2/t1); } } if(fabs(S.top()-(double)tar)<1e-8) { for(int i=0;i<n;++i) { for(int k=0;k<4;++k) { r[k].push(testb[i][k]); for(int j=0;j<(int)op[i].size();++j) { double t1=r[k].top(); r[k].pop(); double t2=r[k].top(); r[k].pop(); if(op[i][j]==0) r[k].push(t2+t1); if(op[i][j]==1) r[k].push(t2-t1); if(op[i][j]==2) r[k].push(t2*t1); if(op[i][j]==3) r[k].push(t2/t1); } } } T temp=(T){r[0].top(),r[1].top(),r[2].top(),r[3].top()}; if(Map[temp])return -1e100; Map[temp]=true; } return S.top(); } void Pr() { Cnt++; string str; for(int i=0;i<n;++i) { str+=‘a‘+i; for(int j=0;j<(int)op[i].size();++j) { if(op[i][j]==0) str+=‘+‘; if(op[i][j]==1) str+=‘-‘; if(op[i][j]==2) str+=‘*‘; if(op[i][j]==3) str+=‘/‘; } } //str是后缀表达式,vec里存的是当前数字的顺序,改下面输出后缀表达式会比较整齐 int t=0; str=EXCHANGE::work(str); for(int i=0;i<(int)str.size();++i) { if(str[i]>=‘a‘ && str[i]<=‘z‘) printf("%d ",vec[t++]); else printf("%c ",str[i]); } printf("\n"); return ; } /* Violent enumeration operator */ void Calc(const int step,const int pos,const int lim) { if(step==n-1) { if(fabs(C()-(double)tar)<1e-8) { Pr(); if(Cnt==trw)throw 0; } return ; } for(int i=pos;i<n;++i) { for(int j=0;j<=lim;++j) { op[i].push_back(j); if(step+1<=i) Calc(step+1,i,lim); op[i].pop_back(); } } return ; } /* Violent enumeration Permutations */ void Dfs(const int step,const int lim) { if(step==n) { try{Calc(0,0,lim);} catch(...){throw 0;} return ; } for(int i=0;i<n;++i) { if(!visited[i]) { visited[i]=true; vec[step]=a[i]; for(int j=0;j<4;++j) testb[step][j]=test[i][j]; Dfs(step+1,lim); visited[i]=false; } } return ; } int main() { printf("Size of Input:\t"); scanf("%d",&n); printf("Target Result:\t"); scanf("%d",&tar); printf("Result limits(0 for no limits): "); scanf("%d",&trw); printf("Input(32bits integers):\n"); for(int i=0;i<n;++i) scanf("%d",&a[i]); Init_random_list(); printf("========================\n"); //这里会优先选择没有乘除的方案 try{Dfs(0,0);}catch(...){} try{Dfs(0,1);}catch(...){} try{Dfs(0,2);}catch(...){} try{Dfs(0,3);}catch(...){} printf("========================\n"); printf("%d Results Found!\n",Cnt); return 0; }
以上是关于[24点计算器][C++版本]无聊拿去玩的主要内容,如果未能解决你的问题,请参考以下文章