速算24点
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5070 Accepted Submission(s): 1310
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 )这个式子无法去掉括号,因此加括号的情况不能省略。
(以上的思路可能有些繁琐,直接暴力任取两个数字来枚举六个运算来计算也是可以的,时间都效率差不多。)
代码如下:
题目链接: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);
}
}
}