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 }