【暴力枚举】速算游戏 fun.pas/c/cpp
来源:互联网 发布:mysql dense rank 编辑:程序博客网 时间:2024/05/17 03:03
速算游戏
fun.pas/c/cpp
源程序名 fun.pas|c|cpp
输入文件名 fun.in
输出文件名 fun.out
时间限制 1s/testcase
空间限制 32MB
问题描述
jyx和cyy打赌,比谁24点算得快,算得慢的那个人请客。24点的规则是这样的:给定4个1..9的整数,用括号改变运算顺序,通过加、减、乘、除通的一系列运算,得到整数24,注意所有中间结果必须是整数(例如(2*2)/4是允许的,而2*(2/4)是不允许的)。为了赢得这个比赛,请写一个程序帮助我作弊,快速地计算出24点。
输入数据
一行 4 个整数,为给定的 4 个数字。输入数据保证有解。
输出数据
一行,以字符串的形式输出结果,注意将每一步的运算的括号补齐(例如(3+5)+6和3*(5+6))如果有多种解答,输出字典顺序最小的一个。
样例输入
2 3 5 7
样例输出
(((3*5)+2)+7)
首先我们可以归纳出大体框架,即 A~B~C~D (ABCD分别代表四个数,~代表符号,数不能重复,符号可以)
然后我们往里面添上括号,就可以得到五种情况
①(((A~B)~C)~D)
②((A~B)~(C~D))
③((A~(B~C))~D)
④(A~((B~C)~D))
⑤(A~(B~(C~D)))
上面五种情况是可以手算出来的,那么剩下需要我们做的就是把数和符号填入,自然而然就想到了深搜全排列!
先全排列数字,每排完一种数字的方案,就排符号的方案,全部完了后就可以得到数字和符号组合的所有方案(注意全排列数字需要hash标记,因为不能重复,但是符号是可以重复的,所以不需要hash标记)
现在就剩下计算的模块了(最恼火的),我们需要根据上面所编排的五种括号的位置,在每次全排列完成后进行一次判断,可行的话就入优先队列(小根堆,要按字典序排序)
一定要注意除法的特殊性,根据题目要求我们可以得到如果是x/y,那么就要满足 x>y>0 并且 x可以整除y,至于代码的实现我们可以写一个函数返回longint,即calc(x,op,y) x和y为两个数,op为符号,不满足上面的条件就返回-1,在每次调用的时候判断是否为-1,是-1就表示当前方案不可行
最后找到可行方案了,就按照当前方案存成字符串string(很烦的),入优先队列(pascal可以写入数组,最后快排)
剩下的就是细节问题了,就不多说了
C++ Code
/*C++ Codehttp://blog.csdn.net/jiangzh7by jiangzh*/#include<cstdio>#include<iostream>#include<cctype>#include<string>#include<queue>#include<algorithm>#include<vector>using namespace std;int a[5],num[5];//a是输入数据 num用来存每次全排列的方案priority_queue<string,vector<string>,greater<string> > q;bool h[5];char op[5]={'*','+','-','/'},opp[5];//op是四种运算符 opp用来存每次全排列的方案int calc(int x,char op,int y){ if(op=='+') return x+y; if(op=='-') return x-y; if(op=='*') return x*y; if(op=='/') if(x>y && y>0 && x%y==0)return x/y;else return -1;//不满足除法要求的就返回-1}void check()//判断当前方案是否可行,可行则入队列{ int temp,temp2; string s; bool flag; // (((A~B)~C)~D) flag=true;//标记是否不满足除法(返回-1),不满足就为false, -----下同 if((temp=calc(num[1],opp[1],num[2]))==-1)flag=false; if((temp=calc(temp,opp[2],num[3]))==-1)flag=false; if((temp=calc(temp,opp[3],num[4]))==-1)flag=false; if(flag && temp==24) { s="(((";s+=(num[1]+'0');s+=opp[1];s+=(num[2]+'0');s+=")";s+=opp[2]; s+=(num[3]+'0');s+=")";s+=opp[3];s+=(num[4]+'0');s+=")"; q.push(s); } // ((A~B)~(C~D)) flag=true; if((temp=calc(num[1],opp[1],num[2]))==-1)flag=false; if((temp2=calc(num[3],opp[3],num[4]))==-1)flag=false; if((temp=calc(temp,opp[2],temp2))==-1)flag=false; if(flag && temp==24) { s="((";s+=(num[1]+'0');s+=opp[1];s+=(num[2]+'0');s+=")";s+=opp[2]; s+="(";s+=(num[3]+'0');s+=opp[3];s+=(num[4]+'0');s+="))"; q.push(s); } // (A~((B~C)~D)) flag=true; if((temp=calc(num[2],opp[2],num[3]))==-1)flag=false; if((temp=calc(temp,opp[3],num[4]))==-1)flag=false; if((temp=calc(num[1],opp[1],temp))==-1)flag=false; if(flag && temp==24) { s="(";s+=(num[1]+'0');s+=opp[1];s+="((";s+=(num[2]+'0');s+=opp[2]; s+=(num[3]+'0');s+=")";s+=opp[3];s+=(num[4]+'0');s+="))"; q.push(s); } // ((A~(B~C))~D) flag=true; if((temp=calc(num[2],opp[2],num[3]))==-1)flag=false; if((temp=calc(num[1],opp[1],temp))==-1)flag=false; if((temp=calc(temp,opp[3],num[4]))==-1)flag=false; if(flag && temp==24) { s="((";s+=(num[1]+'0');s+=opp[1];s+="(";s+=(num[2]+'0');s+=opp[2]; s+=(num[3]+'0');s+="))";s+=opp[3];s+=(num[4]+'0');s+=")"; q.push(s); } // (A~(B~(C~D))) flag=true; if((temp=calc(num[3],opp[3],num[4]))==-1)flag=false; if((temp=calc(num[2],opp[2],temp))==-1)flag=false; if((temp=calc(num[1],opp[1],temp))==-1)flag=false; if(flag && temp==24) { s="(";s+=(num[1]+'0');s+=opp[1];s+="(";s+=(num[2]+'0');s+=opp[2]; s+="(";s+=(num[3]+'0');s+=opp[3];s+=(num[4]+'0');s+=")))"; q.push(s); } }void dfsop(int x){ if(x>3) { //for(int i=1;i<=3;i++) printf("%c ",opp[i]); //printf("\n"); check(); return; } for(int i=0;i<4;i++) { opp[x]=op[i]; dfsop(x+1); }}void dfs(int x){ if(x>4) { //for(int i=1;i<=4;i++) printf("%d ",num[i]); //printf("\n"); dfsop(1);//生成符号的全排列 return; } for(int i=1;i<=4;i++) if(!h[i]) { num[x]=a[i]; h[i]=true; dfs(x+1); h[i]=false; }}int main(){ freopen("fun.in","r",stdin); freopen("fun.out","w",stdout); for(int i=1;i<=4;i++) scanf("%d",&a[i]); dfs(1);//生成数字的全排列 if(!q.empty())//用优先队列储存,直接输出队头字典序小的 { cout<<q.top(); exit(0); } return 0;}
- 【暴力枚举】速算游戏 fun.pas/c/cpp
- 传球游戏(ball.pas/c/cpp)
- 【枚举染色】嗅探器 sniffer.pas/c/cpp/in/out
- mm.cpp/c/pas
- set.cpp/c/pas
- 【模拟 计算几何】连线游戏 lines.pas/c/cpp
- 火星人(martian.pas/c/cpp)
- 飙车[nfs.pas/c/cpp]
- 船(ships.pas/c/cpp)
- 采药(medic.pas/c/cpp)
- 报数( Read . pas / c / cpp )
- 【枚举+优化】【队列操作】【RMQ】奶牛派对 tahort.pas/c/cpp
- 机器分配(machine.c/cpp/pas)
- 硬币找零(coin.c/cpp/pas)
- 编辑距离(edit.c/cpp/pas)
- 逃亡的准备(hallows.pas/c/cpp)
- 整数划分(文件名:separate.c/cpp/pas)
- 配置魔药(medic.pas/c/cpp)
- 【枚举染色】嗅探器 sniffer.pas/c/cpp/in/out
- 【动态规划】Tom的烦恼 tom.pas/c/cpp/in/out
- 使用DTD文档对 xml 1 作业中的xml文档进行约束,其中河北省只能依次包含石家庄市、张家口市、保定市这三个市,保定市可以有多个或者1个,给保定市定义属性编号为ID类型,必须有;属性name为字符
- 【字符串处理】文明的复兴 words.pas/c/cpp/in/out
- [总结] C字符串常用处理函数
- 【暴力枚举】速算游戏 fun.pas/c/cpp
- 【打表】数页码 count.pas/c/cpp
- 【打表】Round Numbers rndnum.pas/c/cpp
- [总结]c++字符串详解
- [程序]自己做了一个测试数据生成器 可以下载
- 单例类
- 【模拟 计算几何】连线游戏 lines.pas/c/cpp
- 【最长上升子序列+二分优化】麻烦的聚餐 egroup.pas/c/cpp
- 【最长下降子序列+二分优化】免费午餐 rqnoj167