Compute 24 每日一题(13)――24点 (分治&递归)


Related: HDU 1427 速算24点-DFS
给玩家4张牌,每张面值1~13,采用+-、*、/以及括号,使其最终结果为24
http://coderchen.blogspot.com/2015/11/compute-24.html
dfs搜索搞定。。。但是这里要注意一些细节,每次计算得到新的数之后最好加入数组做下一次搜索,不然容易出错。
private boolean compute(int[] nums, int target) {
boolean[] visit = new boolean[nums.length];
return helper(nums, visit, target, nums.length);
}

private boolean helper(int[] nums, boolean[] visit, int target, int c) {
if (c == 1) {
for (int i = 0; i < nums.length; i++) {
if (!visit[i]) {
return nums[i] == target;
}
}
else {
for (int i = 0; i < nums.length; i++) {
if (visit[i])
continue;
for (int j = i + 1; j < nums.length; j++) {
if (visit[j])
continue;
int n1 = nums[i];
int n2 = nums[j];
visit[j] = true;
nums[i] = n1 + n2;
if (helper(nums, visit, target, c - 1))
return true;
nums[i] = n1 - n2;
if (helper(nums, visit, target, c - 1))
return true;
nums[i] = n2 - n1;
if (helper(nums, visit, target, c - 1))
return true;
nums[i] = n1 * n2;
if (helper(nums, visit, target, c - 1))
return true;
if (n2 != 0) {
nums[i] = n1 / n2;
if (helper(nums, visit, target, c - 1))
return true;
}
if (n1 != 0) {
nums[i] = n2 / n1;
if (helper(nums, visit, target, c - 1))
return true;
}
nums[i] = n1;
visit[j] = false;
}
}
}
return false;

}

2.分治法
假定集合A={1,2,3,4},首先任意取出两个数,如去除1,2,A=A - {1,2},进行不同的四则运算,1+2=3,1-2=-1, 1*2=2, 1/2=0.5, 将结果再分别加入集合A,可得:
B={3,3,4}, C={-1,3,4}, D={2,3,4}, E={0.5,3,4}四个新的集合:
集合A所有可能的值 F(A) = F(B)+F(C)+F(D)+F(E) 计算规模由4个数降低为3个数
  1. F(Array)  
  2. {  
  3.   if(Array.Length<2)  
  4.   {  
  5.     if(最终结果为24) 输出表达式;  
  6.     else 无法构造   
  7.   }  
  8.   for each(从数组中任意取两个数的组合)  
  9.   {  
  10.       for each(运算符(+, -, *,  /))  
  11.       {  
  12.          1.计算该组合在此运算符下的结果;  
  13.          2.将组合中的两个数从原数组中移除,并将步骤1的结果放入数组;  
  14.          3.对新数组递归调用f,找到一个表达式则返回;  
  15.          4.将步骤1的结果移除,并将该组合中的两个数重新放回该数组;  
  16.        }  
  17.   }  
  18. }  
3.采用分支限界法求解
 任然假定假定集合A,首先采用分治思想,将集合A划分为A1与A-A1,分别对他们俩进行四则运算求解F(A1)和F(A-A1),最后对这两个集合里的元素进行四则运算,所得到的所有集合的并集就是F(A)

  1. #define N   4   // 4张牌,可变  
  2. #define RES 24  // 运算结果为24,可变  
  3. #define EPS 1e-6  
  4.   
  5. struct Elem  
  6. {  
  7.     Elem(double r, string& i):res(r),info(i){}  
  8.     Elem(double r, char* i):res(r),info(i){}  
  9.     double res; // 运算出的数据  
  10.     string info; // 运算的过程  
  11.     bool operator<(const Elem& e) const  
  12.     {  
  13.         return res < e.res; // 在set的红黑树插入操作中需要用到比较操作  
  14.     }  
  15. };  
  16. int A[N];   // 记录N个数据  
  17. //用二进制数来表示集合和子集的概念,0110表示集合包含第2,3个数  
  18. set<Elem> vset[1<<N];   // 包含4个元素的集合共有16个子集0-15  
  19.   
  20. set<Elem>& Fork(int m)  
  21. {  
  22.     // memo递归  
  23.     if (vset[m].size())  
  24.     {  
  25.         return vset[m];  
  26.     }  
  27.     for (int i=1; i<=m/2; i++)//因为分别计算Fork(i)与Fork(m-i),所以计算一半就行了  
  28.         if ((i&m) == i)  
  29.         {  
  30.             set<Elem>s1 = Fork(i);  
  31.             set<Elem>s2 = Fork(m-i);  
  32.             // 得到两个子集合的笛卡尔积,并对结果集合的元素对进行6种运算  
  33.             for (set<Elem>::iterator cit1=s1.begin(); cit1!=s1.end(); cit1++)  
  34.                 for (set<Elem>::iterator cit2=s2.begin(); cit2!=s2.end(); cit2++)  
  35.                 {  
  36.                     string str;  
  37.                     str = "("+cit1->info+"+"+cit2->info+")";  
  38.                     vset[m].insert(Elem(cit1->res+cit2->res,str));  
  39.                     str = "("+cit1->info+"-"+cit2->info+")";  
  40.                     vset[m].insert(Elem(cit1->res-cit2->res,str));  
  41.                     str = "("+cit2->info+"-"+cit1->info+")";;  
  42.                     vset[m].insert(Elem(cit2->res-cit1->res,str));  
  43.                     str = "("+cit1->info+"*"+cit2->info+")";  
  44.                     vset[m].insert(Elem(cit1->res*cit2->res,str));  
  45.                     if (abs(cit2->res)>EPS)   
  46.                     {  
  47.                         str = "("+cit1->info+"/"+cit2->info+")";  
  48.                         vset[m].insert(Elem(cit1->res/cit2->res,str));  
  49.                     }  
  50.                     if (abs(cit1->res)>EPS)  
  51.                     {  
  52.                         str = "("+cit2->info+"/"+cit1->info+")";  
  53.                         vset[m].insert(Elem(cit2->res/cit1->res,str));  
  54.                     }  
  55.                 }  
  56.         }  
  57.         return vset[m];     //这一步一定不要忘了  
  58. }  
  59. int main()  
  60. {  
  61.     int i;  
  62.     for (i=0; i<N; i++)  
  63.         cin >> A[i];  
  64.     // 递归的结束条件;  
  65.     for (i=0; i<N; i++)  
  66.     {  
  67.         char str[10];  
  68.         sprintf(str,"%d",A[i]);  
  69.         vset[1<<i].insert(Elem(A[i],str));  
  70.     }  
  71.     Fork((1<<N)-1);//开始1111 表示四个数;   
  72.     // 显示算出24点的运算过程;  
  73.     for (set<Elem>::iterator it=vset[(1<<N)-1].begin(); it!=vset[(1<<N)-1].end(); it++)  
  74.     {  
  75.         if (abs(it->res-RES) < EPS)  
  76.             cout << it->info << endl;  
  77.     }  
  78. }  
http://blog.csdn.net/tianshuai1111/article/details/7713640
         最直接的方法就是采用穷举法,游戏中可用的运算符只有四种,四个数字每个只能使用一次。
         1)不考虑括号情况
                4个数全排列:4!=24种
                需要三个运算符,且运算符可以重复:4*4*4=64
                总计:1536
         2)考虑括号(是个难点)
                自己想的加括号:四个数有五种加括号方式:  (AB)CD  、 AB(CD)、 A(BC)D 、 A((BC)D) 、 (AB)(CD)、A(B(CD))
                 错误点:这里添加括号的时候,需要把四个数都看成相乘。需要加两个括号来列举比较直观
                                  AB(CD)  =   (AB)(CD)
                 改正后:((AB)C)D  、 (AB)(CD) 、 (A(BC))D 、 A((BC)D) 、A(B(CD))

http://bylijinnan.iteye.com/blog/1606892
  1.      * 1.穷举。计算所有的可能,若能得到24,输出 
  1.     public static boolean compute(double[] number,String[] result,int n){  
  2.         if(n==1){  
  3.             return (Math.abs(number[0]-ResultValue)<DIFF);   //number[0]==ResultValue or not  
  4.         }  
  5.           
  6.         for(int i=0;i<n;i++){  
  7.             for(int j=i+1;j<n;j++){  
  8.                 double a=number[i];  
  9.                 double b=number[j];  
  10.                   
  11.                 String expa=result[i];  
  12.                 String expb=result[j];  
  13.                   
  14.                 //每计算一次,参与运算的数字就少一个。将最后一个数字复制到位置j,可达到缩小(缩短)数组的效果  
  15.                 number[j]=number[n-1];  
  16.                 result[j]=result[n-1];  
  17.                   
  18.                  //加法操作 a+b    
  19.                 number[i] = a+b;   
  20.                 result[i] = '(' + expa + '+' + expb + ')';    
  21.                 if(compute(number,result,n-1)){    
  22.                      return true;    
  23.                 }    
  24.                     
  25.                 //减法操作 a-b    
  26.                 number[i] = a - b;    
  27.                 result[i] = '(' + expa + '-' + expb + ')';    
  28.                 if(compute(number,result,n-1)){    
  29.                      return true;    
  30.                 }    
  31.                     
  32.                 //减法操作 b-a    
  33.                 number[i] = b - a;    
  34.                 result[i] = '(' + expb + '-' + expa + ')';    
  35.                 if(compute(number,result,n-1)){    
  36.                      return true;    
  37.                 }    
  38.                     
  39.                 //乘法操作 a*b     
  40.                 number[i] = a * b;    
  41.                 result[i] = '(' + expa + '*' + expb + ')';    
  42.                 if(compute(number,result,n-1)){    
  43.                      return true;    
  44.                 }    
  45.                     
  46.                 //除法操作 a/b, 如果除数不为0     
  47.                 if(b != 0){    
  48.                     number[i] = a / b;    
  49.                     result[i] = '(' + expa + '/' + expb + ')';    
  50.                     if(compute(number,result,n-1))    
  51.                     {    
  52.                          return true;    
  53.                     }    
  54.                 }                         
  55.                     
  56.                 //除法操作 b/a , 如果除数不为0     
  57.                 if(a != 0){    
  58.                     number[i] = b / a;    
  59.                     result[i] = '(' + expb + '/' + expa + ')';    
  60.                     if(compute(number,result,n-1)){    
  61.                          return true;    
  62.                     }    
  63.                 }    
  64.                     
  65.                 number[i] = a;    
  66.                 number[j] = b;    
  67.                 result[i] = expa;    
  68.                 result[j] = expb;    
  69.             }  
  70.         }  
  71.         return false;  
  72.     }  
 
算法1:
算法1代码如下,我在原来的基础上做了一点改动1、从数组中任选两个数时,保证数对前面没有选择过; 2、通过运算符优先级去除多余的括号;3、选出的两个数相同时,减法和除法只做一次,即只做a-b ,a/b, 不做 b-a,b/a,其中1、3都可以减少冗余计算
 10 //cards[i]的值是通过表达式expr[i]计算而来
 11 //且expr的最后一个运算操作lastop[i]
 12 bool GameRecur(double cards[], string expr[], char lastop[],
 13                const int cardsNum, const int result)
 14 {
 15     if(cardsNum == 1)
 16     {
 17         if(cards[0] == result)
 18         {
 19             //cout<<expr[0]<<endl;
 20             return true;
 21         }
 22         else return false;
 23     }
 24     //从已有数中任选两个,计算得到中间结果,并且和剩余的数一起存在cards数组的前
 25     //cardsNum-1个位置
 26     map<pair<double,double>,bool> selectedPair;
 27     for(int i = 0; i<cardsNum; i++)
 28     {
 29         for(int k  = i+1; k < cardsNum; k++)
 30         {
 31             if( selectedPair.find(pair<double, double>(cards[i], cards[k]))
 32                != selectedPair.end() || selectedPair.find(pair<double, double>
 33                (cards[k], cards[i])) != selectedPair.end() )
 34                 break;
 35             else
 36             {
 37                 selectedPair[pair<double,double>(cards[i], cards[k])] = 1;
 38                 selectedPair[pair<double,double>(cards[k], cards[i])] = 1;
 39             }
 40             //上面的代码保证选出的数对不重复
 41             double a = cards[i], b = cards[k];
 42             cards[k] = cards[cardsNum-1];
 43             string expra = expr[i], exprb = expr[k];
 44             expr[k] = expr[cardsNum-1];
 45             char lastop_a = lastop[i], lastop_b = lastop[k];
 46             lastop[k] = lastop[cardsNum-1];
 47 
 48             cards[i] = a + b;
 49             expr[i] = expra + '+' + exprb;
 50             lastop[i] = '+';
 51             if(GameRecur(cards, expr, lastop, cardsNum-1, result))
 52                 return true;
 53 
 54             cards[i] = a - b;
 55             if('+' == lastop_b || '-' == lastop_b)
 56                 expr[i] = expra + '-' + '(' + exprb + ')';
 57             else expr[i] = expra + '-' + exprb;
 58             lastop[i] = '-';
 59             if(GameRecur(cards, expr, lastop, cardsNum-1, result))
 60                 return true;
 61 
 62             if(a != b)
 63             {
 64                 cards[i] = b - a;
 65                 if('+' == lastop_a || '-' == lastop_a)
 66                     expr[i] = exprb + '-' + '(' + expra + ')';
 67                 else expr[i] = exprb + '-' + expra;
 68                 lastop[i] = '-';
 69                 if(GameRecur(cards, expr, lastop, cardsNum-1, result))
 70                     return true;
 71             }
 72 
 73             cards[i] = a * b;
 74             if('-' == lastop_a || '+' == lastop_a)
 75                 expr[i] = '(' + expra + ')' + '*';
 76             else expr[i] = expra + '*';
 77             if('*' == lastop_b || ' ' == lastop_b)
 78                 expr[i] += exprb;
 79             else expr[i] += '(' + exprb + ')';
 80             lastop[i] = '*';
 81             if(GameRecur(cards, expr, lastop, cardsNum-1, result))
 82                 return true;
 83 
 84             if(b != 0)
 85             {
 86                 cards[i] = a / b;
 87                 if('-' == lastop_a || '+' == lastop_a)
 88                     expr[i] = '(' + expra + ')' + '/';
 89                 else expr[i] = expra + '/';
 90                 if(' ' == lastop_b)
 91                     expr[i] += exprb;
 92                 else expr[i] += '(' + exprb + ')';
 93                 lastop[i] = '/';
 94                 if(GameRecur(cards, expr, lastop, cardsNum-1, result))
 95                     return true;
 96             }
 97 
 98             if(a != 0 && a!= b)
 99             {
100                 cards[i] = b / a;
101                 if('-' == lastop_b || '+' == lastop_b)
102                     expr[i] = '(' + exprb + ')' + '/';
103                 else expr[i] = exprb + '/';
104                 if(' ' == lastop_a)
105                     expr[i] += expra;
106                 else expr[i] += '(' + expra + ')';
107                 lastop[i] = '/';
108                 if(GameRecur(cards, expr, lastop, cardsNum-1, result))
109                     return true;
110             }
111 
112             //把选出来的两个数放回原位
113             cards[i] = a;
114             cards[k] = b;
115             expr[i] = expra;
116             expr[k] = exprb;
117             lastop[i] = lastop_a;
118             lastop[k] = lastop_b;
119         }
120     }
121     return false;
122 }
对算法1稍作修改可以输出全部的表达式:
//cards[i]的值是通过表达式expr[i]计算而来
  3 //且expr的最后一个运算操作lastop[i]
  4 bool GameRecur_all(double cards[], string expr[], char lastop[],
  5                    const int cardsNum, const int result)
  6 {
  7     if(cardsNum == 1)
  8     {
  9         if(cards[0] == result)
 10         {
 11             cout<<expr[0]<<endl;
 12             return true;
 13         }
 14         else return false;
 15     }
 16     //从已有数中任选两个,计算得到中间结果,并且和剩余的数一起存在cards数组的前
 17     //cardsNum-1个位置
 18     map<pair<double,double>,bool> selectedPair;
 19     bool res = false;
 20     for(int i = 0; i<cardsNum; i++)
 21     {
 22         for(int k  = i+1; k < cardsNum; k++)
 23         {
 24             if( selectedPair.find(pair<double, double>(cards[i], cards[k]))
 25                != selectedPair.end() || selectedPair.find(pair<double, double>
 26                (cards[k], cards[i])) != selectedPair.end() )
 27                 break;
 28             else
 29             {
 30                 selectedPair[pair<double,double>(cards[i], cards[k])] = 1;
 31                 selectedPair[pair<double,double>(cards[k], cards[i])] = 1;
 32             }
 33             //上面的代码保证选出的数对不重复
 34             double a = cards[i], b = cards[k];
 35             cards[k] = cards[cardsNum-1];
 36             string expra = expr[i], exprb = expr[k];
 37             expr[k] = expr[cardsNum-1];
 38             char lastop_a = lastop[i], lastop_b = lastop[k];
 39             lastop[k] = lastop[cardsNum-1];
 40 
 41             cards[i] = a + b;
 42             expr[i] = expra + '+' + exprb;
 43             lastop[i] = '+';
 44             res = GameRecur_all(cards, expr, lastop, cardsNum-1, result)
 45                 || res;
 46 
 47             cards[i] = a - b;
 48             if('+' == lastop_b || '-' == lastop_b)
 49                 expr[i] = expra + '-' + '(' + exprb + ')';
 50             else expr[i] = expra + '-' + exprb;
 51             lastop[i] = '-';
 52             res = GameRecur_all(cards, expr, lastop, cardsNum-1, result) || res;
 53 
 54             if(a != b)
 55             {
 56                 cards[i] = b - a;
 57                 if('+' == lastop_a || '-' == lastop_a)
 58                     expr[i] = exprb + '-' + '(' + expra + ')';
 59                 else expr[i] = exprb + '-' + expra;
 60                 lastop[i] = '-';
 61                 res = GameRecur_all(cards, expr, lastop, cardsNum-1, result)
 62                     || res;
 63             }
 64 
 65             cards[i] = a * b;
 66             if('-' == lastop_a || '+' == lastop_a)
 67                 expr[i] = '(' + expra + ')' + '*';
 68             else expr[i] = expra + '*';
 69             if('*' == lastop_b || ' ' == lastop_b)
 70                 expr[i] += exprb;
 71             else expr[i] += '(' + exprb + ')';
 72             lastop[i] = '*';
 73             res = GameRecur_all(cards, expr, lastop, cardsNum-1, result)
 74                 || res;
 75 
 76             if(b != 0)
 77             {
 78                 cards[i] = a / b;
 79                 if('-' == lastop_a || '+' == lastop_a)
 80                     expr[i] = '(' + expra + ')' + '/';
 81                 else expr[i] = expra + '/';
 82                 if(' ' == lastop_b)
 83                     expr[i] += exprb;
 84                 else expr[i] += '(' + exprb + ')';
 85                 lastop[i] = '/';
 86                 res = GameRecur_all(cards, expr, lastop, cardsNum-1, result)
 87                     || res;
 88             }
 89 
 90             if(a != 0 && a!= b)
 91             {
 92                 cards[i] = b / a;
 93                 if('-' == lastop_b || '+' == lastop_b)
 94                     expr[i] = '(' + exprb + ')' + '/';
 95                 else expr[i] = exprb + '/';
 96                 if(' ' == lastop_a)
 97                     expr[i] += expra;
 98                 else expr[i] += '(' + expra + ')';
 99                 lastop[i] = '/';
100                 res = GameRecur_all(cards, expr, lastop, cardsNum-1, result)
101                      || res;
102             }
103 
104             //把选出来的两个数放回原位
105             cards[i] = a;
106             cards[k] = b;
107             expr[i] = expra;
108             expr[k] = exprb;
109             lastop[i] = lastop_a;
110             lastop[k] = lastop_b;
111         }
112     }
113     return res;
114 }
算法2
算法2代码如下,集合用stl中的set表示,代码中变量名保持和书中一致
调用函数PointGame2即可返回表达式结果,调用方式同算法1 
10 struct setNode
11 {
12     double val;
13     string expr;//运算出val的表达式
14     setNode(double v, string e):val(v),expr(e){}
15     setNode(double v, char e[]):val(v),expr(e){}
16     bool operator < (const setNode &s)const
17     {
18         return val < s.val;
19     }
20 };
21 
22 void f(const int i, set<setNode> s[], const double result)
23 {
24     int len = sizeof(s)/sizeof(set<setNode>) - 1;//len = 2^n - 1
25     if(s[i].empty() == true)
26         for(int x = 1; x <= i/2; x++)
27             if((x&i) == x)
28             {
29                 set<setNode>::iterator it1, it2;
30                 // s[i] U= fork(s[x] ,s[i-x])
31                 for(it1 = s[x].begin(); it1 != s[x].end(); it1++)
32                     for(it2 = s[i-x].begin(); it2 != s[i-x].end(); it2++)
33                     {
34                         string expr;
35                         double tempresult;
36                         tempresult = it1->val + it2->val;
37                         expr = '(' + it1->expr + '+' + it2->expr + ')';
38                         s[i].insert(setNode(tempresult, expr));
39                         //计算f[2^n-1]时,若计算好了结果则可以停止
40                         if(i == len && tempresult == result)return;
41 
42 
43                         tempresult = it1->val - it2->val;
44                         expr = '(' + it1->expr + '-' + it2->expr + ')';
45                         s[i].insert(setNode(tempresult, expr));
46                         if(i == len && tempresult == result)return;
47                         if(it1->val != it2->val)
48                         {
49                             tempresult = it2->val - it1->val;
50                             expr = '(' + it2->expr + '-' + it1->expr + ')';
51                             s[i].insert(setNode(tempresult, expr));
52                             if(i == len && tempresult == result)return;
53                         }
54 
55                         tempresult = it1->val * it2->val;
56                         expr = '(' + it1->expr + '*' + it2->expr + ')';
57                         s[i].insert(setNode(tempresult, expr));
58                         if(i == len && tempresult == result)return;
59 
60                         if(it2->val != 0)
61                         {
62                             tempresult = it1->val / it2->val;
63                             expr = '(' + it1->expr + '/' + it2->expr + ')';
64                             s[i].insert(setNode(tempresult, expr));
65                             if(i == len && tempresult == result)return;
66                         }
67                         if(it1->val != it2->val && it1->val != 0)
68                         {
69                             tempresult = it2->val / it1->val;
70                             expr = '(' + it2->expr + '/' + it1->expr + ')';
71                             s[i].insert(setNode(tempresult, expr));
72                             if(i == len && tempresult == result)return;
73                         }
74                     }
75             }
76 }
77 
78 string PointGame2(int cards[], const int cardsNum, const int result)
79 {
80     int len = 1<<cardsNum;
81     set<setNode> S[len]; //对应文章中的数组S
82     //初始化只有一个元素的子集,j = 2^i,即只有一个2进制位是1
83     for(int i = 0, j = 1; i < cardsNum; i++, j = j<<1)
84     {
85         char buf[30];
86         sprintf(buf, "%d", cards[i]);
87         S[j].insert(setNode(cards[i],buf));
88     }
89     for(int i = 1; i <= len - 1; i++)
90         f(i, S, result);
91     for(set<setNode>::iterator it = S[len-1].begin();
92         it != S[len-1].end(); it++)
93         {
94             if(it->val == result)
95                 return it->expr;
96         }
97     return "-1";
98 }


  1.      * 2.分治。引入集合,去重。另外,利用x=5=(0101)来表示(a0,a1,a2,a3)的子集(a1,a3)是非常巧妙的 
  1.     //方法2  
  2.     private static final int n=CardsNumber;  
  3.     private static final int m=(1<<n)-1;  //(10000)-1=(1111)=15  
  4.     private static List<Node>[] S;  
  5.       
  6.     public static boolean compute(int[] number){  
  7.         S=new ArrayList[m+1];  
  8.         //(a0,a1,a2,a3)的子集(a0),(a1),(a2),(a3)只有一个元素,不用运算直接返回即可  
  9.         for(int j=0;j<n;j++){  
  10.             int v=number[j];  
  11.             Node node=new Node((0.0+v),(""+v));  
  12.             List<Node> Si=new ArrayList<Node>();  
  13.             Si.add(node);  
  14.             int i=1<<j;  
  15.             S[i]=Si;  
  16.         }  
  17.           
  18.         for(int i=1;i<=m;i++){  
  19.             List<Node> Si=fun(i);  
  20.             S[i]=Si;  
  21.         }  
  22.           
  23.         List<Node> Sm=S[m];  
  24.         for(Node v:Sm){  
  25.             if(Math.abs(v.value-ResultValue)<DIFF){  
  26.                 System.out.println("2. "+v.exp);  
  27.                 return true;  
  28.             }  
  29.         }  
  30.           
  31.         return false;  
  32.     }  
  33.       
  34.     //递归求S[i]  
  35.     public static List<Node> fun(int i){  
  36.         List<Node> si=S[i];  
  37.         if(si!=null&&!si.isEmpty()){  
  38.             return si;  
  39.         }  
  40.         si=new ArrayList<Node>();  
  41.         for(int x=1;x<i;x++){  
  42.             if((x&i)==x){   //确保x是i的子集  
  43.                 List<Node> sx=fun(x);  
  44.                 List<Node> s_x=fun(i-x);  
  45.                 si.addAll(fork(sx,s_x));  
  46.             }  
  47.               
  48.         }  
  49.         return si;  
  50.     }  
  51.       
  52.     //集合里元素两两运算并去重  
  53.     public static List<Node> fork(List<Node> sx,List<Node> s_x){  
  54.         Set<Node> set=new HashSet<Node>();  
  55.         for(int i=0,m=sx.size();i<m;i++){  
  56.             for(int j=0,n=s_x.size();j<n;j++){  
  57.                 Node a=sx.get(i);  
  58.                 Node b=s_x.get(j);  
  59.                 set.add(new Node(a.value+b.value,"("+a.exp+"+"+b.exp+")"));  
  60.                 set.add(new Node(a.value-b.value,"("+a.exp+"-"+b.exp+")"));  
  61.                 set.add(new Node(b.value-a.value,"("+b.exp+"-"+a.exp+")"));  
  62.                 set.add(new Node(a.value*b.value,"("+a.exp+"*"+b.exp+")"));  
  63.                 if(b.value!=0){  
  64.                     set.add(new Node(a.value/b.value,"("+a.exp+"/"+b.exp+")"));  
  65.                 }  
  66.                 if(a.value!=0){  
  67.                     set.add(new Node(b.value/a.value,"("+b.exp+"/"+a.exp+")"));  
  68.                 }  
  69.             }  
  70.         }  
  71.         List<Node> si=new ArrayList<Node>(set);  
  72.         return si;  
  73.     }  
  74.       
  75.       
  76.     static class Node{  
  77.         double value;   //表达式的值   
  78.         String exp;     //表达式  
  79.         Node(double value,String exp){  
  80.             this.value=value;  
  81.             this.exp=exp;  
  82.         }  
  83.         public boolean equals(Object o) {  
  84.                if (!(o instanceof Node))  
  85.                    return false;  
  86.                Node node = (Node) o;  
  87.                return Double.doubleToLongBits(this.value)==  
  88.                         Double.doubleToLongBits(node.value);  
  89.                         //&&this.exp.equals(node.exp);  //只关心值是否相等,不关心表达式  
  90.         }    
  91.         public int hashCode() {  
  92.                int result = 17;  
  93.                long tolong = Double.doubleToLongBits(value);  
  94.                result = 37 * result + (int) (tolong ^ (tolong >>> 32));  
  95.                //result = 37 * result + exp.hashCode();  
  96.                return result;  
  97.             }  
  98.     } 

X. Iterative Version
http://www.iteye.com/topic/312476
24点游戏规则:任取1-9之间的4个数字,用+-*/()连结成算式,使得式子的计算结果为24。估计很多人都玩过用扑克牌玩的那种,印象中10也算在内的,两人各出2张牌,谁先算出来谁赢,赢家收回已经算过的4张牌。最后看谁手里的牌多。 
这个程序实现使用穷举的方法,将所有可能的排列穷举出来,最后将每个排列中计算出结果。计算结果时,将前两个作为一组、后两个数作为一组,分别计算出各组的结果,再对获得的两个组结果进行计算。由于是排列,分前后两组进行计算就可满足所有可能的计算。 
  1.     public static void evaluate(int[] v){  
  2.         int idx=0;  
  3.         for(int a=0;a<4;a++)  
  4.             for(int b=0;b<4;b++)  
  5.                 for (int c=0;c<4;c++)  
  6.                     for (int d=0;d<4;d++){  
  7.                     if (a!=b && a!=c && a!=d && b!=c && b!=d && c!=d){  
  8.                         idx++;  
  9.                         check(v,new int[]{a,b,c,d});  
  10.                     }  
  11.                 }  
  12.     }  
  13.     static char[] op={'+','-','*','/'};  
  14.     public static void check(int[] v,int[] idx){  
  15.           
  16.         for(int o=0;o<4;o++){  
  17.             for(int p=0;p<4;p++){  
  18.                 for(int t=0;t<4;t++){  
  19.                     if (op(op[p],op(op[o],v[idx[0]],v[idx[1]]),op(op[t],v[idx[2]],v[idx[3]]))==24){  
  20.                         System.out.println(String.format("(%1$d %2$c %3$d) %4$c (%5$d %6$c %7$d)",  
  21.                                 v[idx[0]],op[o],v[idx[1]],op[p],v[idx[2]],op[t],v[idx[3]]));  
  22.                     }  
  23.                 }  
  24.             }  
  25.         }  
  26.     }  
  27.   
  28.     public static int op(char op,int v1,int v2){  
  29.         switch(op){  
  30.         case '+':  
  31.             return v1+v2;  
  32.         case '-':  
  33.             return v1-v2;  
  34.         case '*':  
  35.             return v1*v2;  
  36.         case '/':  
  37.             if (v2==0return -111;  
  38.             if (v1%v2!=0return -111;  
  39.             return v1/v2;  
  40.         default:  
  41.                 return 0;  
  42.         }  
  43.     }  
http://www.cppblog.com/flyinghearts/archive/2010/08/01/121907.html
bool calc(int src[], size_t N, double M = 24.0) 8{ 9  if (N == 0 || src == NULL) return false;10  set<double> result[1 << N];11  for (size_t i = 0; i < N; ++i) result[1<<i].insert((double)src[i]); 12  13  for (size_t i =1; i < (1<<N); ++i) {14    for (size_t j = 1; j <= (i >> 1); ++j) {15       if ((i & j) != j) continue;16       for (set<double>::iterator p = result[j].begin(); p != result[j].end(); ++p) {17         double va = *p;18         size_t k = i ^ j;19         for (set<double>::iterator q = result[k].begin(); q != result[k].end(); ++q) {20           double vb = *q;21           result[i].insert(va + vb);22           result[i].insert(va - vb);23           result[i].insert(vb - va);24           result[i].insert(va * vb);25           if (vb != 0.0) result[i].insert(va / vb);26           if (va != 0.0) result[i].insert(vb / va);27         }
28       }

29    }
 30  }

31  32  size_t j = (1 << N) - 1;33  const double zero = 1e-9;34  for (set<double>::iterator p = result[j].begin(); p != result[j].end(); ++p) {35    if (fabs(*- M) < zero) return true;36  }
37  return false;38}

http://www.oschina.net/code/snippet_1377254_35910
http://www.blogjava.net/comic222/archive/2009/01/06/250101.html
http://rosettacode.org/wiki/24_game/Solve#Java
Read full article from 每日一题(13)――24点 (分治&递归) - 小熊不去实验室 - 博客频道 - CSDN.NET

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts