您的位置:首页 > 编程语言 > Java开发

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

2017-03-27 18:19 337 查看

速算24点

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

[/align]

[align=left]Problem Description[/align]
速算24点相信绝大多数人都玩过。就是随机给你四张牌,包括A(1),2,3,4,5,6,7,8,9,10,J(11),Q(12),K(13)。要求只用'+','-','*','/'运算符以及括号改变运算顺序,使得最终运算结果为24(每个数必须且仅能用一次)。游戏很简单,但遇到无解的情况往往让人很郁闷。你的任务就是针对每一组随机产生的四张牌,判断是否有解。我们另外规定,整个计算过程中都不能出现小数。

 

[align=left]Input[/align]
每组输入数据占一行,给定四张牌。

 

[align=left]Output[/align]
每一组输入数据对应一行输出。如果有解则输出"Yes",无解则输出"No"。

 

[align=left]Sample Input[/align]

A 2 3 6
3 3 8 8

 

[align=left]Sample Output[/align]

Yes
No

 

[align=left]Author[/align]
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);
}
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: