本博客rss订阅地址: http://feed.cnblogs.com/blog/u/147990/rss

编程之美 1.16 24点游戏

 编程之美电子书下载

24点游戏大家都知道:4张牌,可以进行+ - * / 四种运算,可以使用括号,每个牌用一次,任意组合构造表达式使结果为24。

扩展问题:n个整数,四种运算,可使用括号,每个数字使用一次,使表达式结果为 k

下面的算法1和算法2都是穷举,只是穷举的方式不一样,以下给出的两个算法代码都可以计算扩展问题。可能是集合操作原因,算法1的速度明显比算法2快

书上分析如下                                                                                                                               本文地址

 

 

算法1:

算法1代码如下,我在原来的基础上做了一点改动1、从数组中任选两个数时,保证数对前面没有选择过; 2、通过运算符优先级去除多余的括号;3、选出的两个数相同时,减法和除法只做一次,即只做a-b ,a/b, 不做 b-a,b/a,其中1、3都可以减少冗余计算

调用函数PointGame即可返回表达式结果                                                                                                     本文地址

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<string>
  4 #include<map>
  5 #include<set>
  6 #include<cmath>
  7 #include<ctime>
  8 using namespace std;
  9 
 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 }
123 
124 //cards 输入的牌
125 //cardsNum 牌的数目
126 //result 想要运算得到的结果
127 string PointGame(int cards[], const int cardsNum, const int result)
128 {
129     string expr[cardsNum];
130     char lastop[cardsNum];
131     double cardsCopy[cardsNum];
132     for(int i = 0; i < cardsNum; i++)
133     {
134         char buf[30];
135         sprintf(buf, "%d", cards[i]);
136         expr[i] = buf;
137         lastop[i] = ' ';//表示cardsCopy[i]是不经过任何运算的原始数据
138         cardsCopy[i] = cards[i];
139     }
140     if(GameRecur(cardsCopy, expr, lastop, cardsNum, result))
141         return expr[0];
142     else return "-1";
143 }
View Code

对算法1稍作修改可以输出全部的表达式:

  1 //------------------------------------------------------------算法1输出所有组合
  2 //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 }
115 
116 //cards 输入的牌
117 //cardsNum 牌的数目
118 //result 想要运算得到的结果
119 void PointGame_all(int cards[], const int cardsNum, const int result)
120 {
121     string expr[cardsNum];
122     char lastop[cardsNum];
123     double cardsCopy[cardsNum];
124     for(int i = 0; i < cardsNum; i++)
125     {
126         char buf[30];
127         sprintf(buf, "%d", cards[i]);
128         expr[i] = buf;
129         lastop[i] = ' ';//表示cardsCopy[i]是不经过任何运算的原始数据
130         cardsCopy[i] = cards[i];
131     }
132     if(GameRecur_all(cardsCopy, expr, lastop, cardsNum, result) == false)
133         cout<<"-1\n";
134 }
View Code

 

 


 

算法2

算法2代码如下,集合用stl中的set表示,代码中变量名保持和书中一致

调用函数PointGame2即可返回表达式结果,调用方式同算法1                                                                    本文地址

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<string>
 4 #include<map>
 5 #include<set>
 6 #include<cmath>
 7 #include<ctime>
 8 using namespace std;
 9 
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 }
View Code

 【版权声明】转载请注明出处:http://www.cnblogs.com/TenosDoIt/p/3407636.html

posted @ 2013-11-04 22:57  tenos  阅读(5221)  评论(2编辑  收藏  举报

本博客rss订阅地址: http://feed.cnblogs.com/blog/u/147990/rss

公益页面-寻找遗失儿童