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
Yes
No
解体思路:第一次写的时候用了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;
}
本文介绍了一种解决速算24点问题的有效算法。通过深度优先搜索(DFS)方法,文章详细解释了如何判断四张牌能否通过加、减、乘、除运算得到24,并提供了一个能够有效避免重复计算的实现方案。

534

被折叠的 条评论
为什么被折叠?



