hdu 1427 速算24点(java,DFS,全排列)

速算24点

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5070    Accepted Submission(s): 1310



Problem 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
 

Author
LL

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1427
解题思路:之前没理解清楚题意,原来给定的牌不是按顺序的,牌的顺序可以打乱,因此要用到全排列来枚举四张牌的顺序。+,-,*,/和()运算用DFS来枚举,cur1代表前一个数或前一个运算结果,cur2代表后一个数或后一个运算结果,DFS分两种情况(@表示运算符):
                 (1)不加括号,按顺序:DFS(cur1@cur2,a[dex+1],dex+1);   //计算完前两个数,再计算数组里的下一个数。
                 (2)后面的数加括号,即先运算后面的数cur1先放着:DFS(cur1,cur2+a[dex+1],dex+1); //先计算后两个数,把计算结果赋给cur2。
DFS的两种情况覆盖的情况有:(1)a @ b @ c @ d
                                                  (2)a @ ( b @ c ) @ d
                                                  (3)a @ ( b @ c  @ d )
                                                  (4)a @  b  @ ( c  @ d )
还有一种情况  :a @ [  b @ ( c  @ d ) ] 转换成了在全排列中的 b @ ( c @ d ) @ a。
在思考过程中想到,既然有全排列,那不加括号时会不会覆盖到所有情况呢?可以看出:
(2)a @ ( b @ c ) @ d 这个式子可以转变为 b @  c @ a @ d ;
(3)a @ ( b @ c  @ d )这个式子可以转变为 b @ c @ d  @ a ;
但是(4)a @  b  @ ( c  @ d )这个式子无法去掉括号,因此加括号的情况不能省略。

(以上的思路可能有些繁琐,直接暴力任取两个数字来枚举六个运算来计算也是可以的,时间都效率差不多。)

代码如下:
import java.util.*;

public class Main {
	
	public static int[] a = new int[5];
	public static boolean flog;
	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()){
			String str = sc.nextLine();
			int cnt=0;
			for(int i=0;i<str.length();i++){
				char c = str.charAt(i);
				if(i+1<str.length() && c=='1' && str.charAt(i+1)=='0'){
					a[cnt++] = 10;
				}else if(c>='2' && c<='9'){
					a[cnt++] = c-'0';
					continue;
				}
				switch (c){
				case 'A': a[cnt++] = 1;break;
				case 'J': a[cnt++] = 11;break;
				case 'Q': a[cnt++] = 12;break;
				case 'K': a[cnt++] = 13;break;
				}
			}
			
			flog = false;
			permutation(a,0,3);
			
			if(flog){
				System.out.println("Yes");
			}else{
				System.out.println("No");
			}					
		}
	}
	
	public static void permutation(int[] num,int start,int end){   //写全排列
		if(flog){
			return;
		}
		if(start==end){                      //每生成一次全排列,进行一次运算
			DFS(a[0],a[1],1);
			return ;
		}
		for(int i=start;i<=end;i++){          //每次一个固定的数依次和后面的数交换位置
			int temp = num[start];
			num[start] = num[i];
			num[i] = temp;
			
			permutation(num,start+1,end);      //通过递归的每一层实现后面数字的全排列
			
			temp = num[start];                 //递归回来之后要恢复顺序,保证每次是两两交换,其他数字位置保持不变
			num[start] = num[i];
			num[i] = temp;
		}
	}
	
	public static void DFS(int cur1,int cur2,int dex){    //用DFS枚举计算
		if(flog){
			return;
		}
		if(dex == 3){
			if(cur1+cur2==24 || cur1-cur2==24 || cur1*cur2==24 ){
				flog = true ; 
			}else if(cur2 !=0 && cur1%cur2==0 &&cur1/cur2==24){
				flog = true;
			}
			return;
		}
		DFS(cur1+cur2,a[dex+1],dex+1);      //没有括号的情况
		DFS(cur1-cur2,a[dex+1],dex+1);      //“-”“/”运算的结果和数字的前后顺序有关,因此都有两种情况
		DFS(cur2-cur1,a[dex+1],dex+1);
		DFS(cur1*cur2,a[dex+1],dex+1);
		if(cur2!=0 && cur1%cur2 == 0 ){    //因为要保证除数不为0且除法运算后不出现小数
			DFS(cur1/cur2,a[dex+1],dex+1);
		}
		if(cur1!=0 && cur2%cur1 == 0){
			DFS(cur2/cur1,a[dex+1],dex+1);
		}
		
		DFS(cur1,cur2+a[dex+1],dex+1);     //有括号的情况
		DFS(cur1,cur2-a[dex+1],dex+1);
		DFS(cur1,a[dex+1]-cur2,dex+1);
		DFS(cur1,cur2*a[dex+1],dex+1);
		if(a[dex+1]!=0 && cur2%a[dex+1] == 0 ){
			DFS(cur1,cur2/a[dex+1],dex+1);
		}
		if(cur2!=0 && a[dex+1]%cur2==0){
			DFS(cur1,a[dex+1]/cur2,dex+1);
		}
	}

}




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值