Description
速算24点相信绝大多数人都玩过。就是随机给你四张牌,包括A(1),2,3,4,5,6,7,8,9,10,J(11),Q(12),K(13)。要求只用'+','-','*','/'运算符以及括号改变运算顺序,使得最终运算结果为24(每个数必须且仅能用一次)。游戏很简单,但遇到无解的情况往往让人很郁闷。你的任务就是针对每一组随机产生的四张牌,判断是否有解。我们另外规定,整个计算过程中都不能出现小数。
Input
每组输入数据占一行,给定四张牌。
Output
每一组输入数据对应一行输出。如果有解则输出"Yes",无解则输出"No"。
Sample Input
A 2 3 6 3 3 8 8
Sample Output
YesNo
解体思路:第一次写的时候用了bfs,先枚举每个数做起点,再枚举不同的运算,在不同运算中再枚举不同的数,结果超时了.看了czy的博客,按他的思路写了dfs.在理解基本思想时,可以这样想,把数放在队列里,每次可以取两个不同的数,作不同的运算,取过的数剔出队列,那么取3次就可以让4个数每个数都参与过运算,且只用一次,从而也知道是否能组成24.在最开始获取四个数时,要注意数字含10这种情况.
代码如下:
#include<stdio.h> #include<string.h> using namespace std; int num[110]; int vist[110]; int dfs(int use,int toal){ int i,j; if(use==4){ if(num[toal-1]==24)//下表从0开始 return 1; else return 0; } for(i=0;i<toal-1;i++){//将计算平均分成两部分 if(vist[i]) continue; vist[i]=true; for(j=i+1;j<toal;j++){ if(vist[j]) continue; vist[j]=true; num[toal]=num[i]+num[j];if(dfs(use+1,toal+1))return 1; num[toal]=num[i]-num[j];if(dfs(use+1,toal+1)) return 1; num[toal]=num[j]-num[i];if(dfs(use+1,toal+1)) return 1; num[toal]=num[i]*num[j];if(dfs(use+1,toal+1)) return 1; if(num[j]){ if(num[i]%num[j]==0){ num[toal]=num[i]/num[j]; if(dfs(use+1,toal+1)) return 1; } } if(num[i]){ if(num[j]%num[i]==0){ num[toal]=num[j]/num[i]; if(dfs(use+1,toal+1)) return 1; } } vist[j]=false; } vist[i]=false; } return 0; } int main(){ char s[20]; int i,flag,k,l; while(gets(s)!=NULL){ k=0; l=strlen(s); for(i=0;i<l;i++){//获得四个数 if(s[i]=='1'&&s[i+1]=='0'){ num[k++]=10; i++; } else if(s[i]==' ') continue; else{ if(s[i]=='A') num[k++]=1; else if(s[i]=='J') num[k++]=11; else if(s[i]=='Q') num[k++]=12; else if(s[i]=='K') num[k++]=13; else num[k++]=s[i]-'0'; } } //printf("%d %d %d %d",num[0],num[1],num[2],num[3]); memset(vist,false,sizeof(vist)); if(dfs(1,4)) printf("Yes\n"); else printf("No\n"); } return 0; }
顺便附上我的超时代码:#include<stdio.h> #include<string.h> #include<queue> using namespace std; struct stu{ int n[4]; int res; }; int num[4]; bool bfs(stu star){ int i,j; stu node; queue<stu> q; while(!q.empty()) q.pop(); q.push(star); stu cur; while(!q.empty()){ star=q.front(); q.pop(); if(star.n[0]==1&&star.n[1]==1&&star.n[2]==1&&star.n[3]==1&&star.res==24) return true; for(i=1;i<=4;i++){ if(i==1){//加 for(j=0;j<4;j++){ cur=star; if(cur.n[j]==0){ cur.n[j]=1; cur.res+=num[j]; q.push(cur); } } } else if(i==2){//减 for(j=0;j<4;j++){ cur=star; if(cur.n[j]==0){ cur.n[j]=1; cur.res-=num[j]; q.push(cur); } } } else if(i==3){//乘 for(j=0;j<4;j++){ cur=star; if(cur.n[j]==0){ cur.n[j]=1; cur.res*=num[j]; q.push(cur); } } } else if(i==4){//除 for(j=0;j<4;j++){ cur=star; if(cur.n[j]==0){ if(cur.res%num[j]==0) { cur.n[j]=1; cur.res/=num[j]; q.push(cur); } } } } } } return false; } int main(){ char s[20]; int i,flag,k,l; while(gets(s)!=NULL){ k=0; l=strlen(s); for(i=0;i<l;i++){//获得四个数 if(s[i]=='1'&&s[i+1]=='0'){ num[k++]=10; i++; } else if(s[i]==' ') continue; else{ if(s[i]=='A') num[k++]=1; else if(s[i]=='J') num[k++]=11; else if(s[i]=='Q') num[k++]=12; else if(s[i]=='K') num[k++]=13; else num[k++]=s[i]-'0'; } } flag=0; for(i=0;i<4;i++){ stu star;//枚举每个数作为开头的情况 star.res=num[i]; star.n[0]=star.n[1]=star.n[2]=star.n[3]=0; star.n[i]=1; if(bfs(star)){ flag=1; break; } } if(flag) printf("Yes\n"); else printf("No\n"); } return 0; }