【算法29】速算24

问题描述

题目来源:PAT ds 2-08

给定四个数字a, b, c, d,取值范围为[1, 13];添加合适的运算符 + , - , * , /, 和括号(, )使得表达式等于24,给出一种可能的表达式方案;如果不可能则返回-1。

例如:输入2, 3, 12, 12, 输出 ((3-2)*12) + 12.

        输入5, 5, 5, 2, 输出-1.

问题分析

这个题目似乎没有好的算法,只能暴力搜索。

    首先对于所有给个数字进行全排列,总过有$A_4^4 = 24$中排列方式;

    然后对于每一种排列方式,需要添加三个运算符,每个运算符有加减乘除四种选择,总共有$4*4*4 = 64$中可能

    最后对于得到的表达式进行加括号以改变优先级,总共只有5种加括号的方式:

  • (A @ B)@(C@D);
  • (A@(B@C))@D;
  • ((A@B)@C)@D;
  • A((B@C)@D);
  • A@(B@(C@D));

因而所有可能的情况有 $24 * 64 * 5 = 7680$种选择。

定义子函数int calcluateBinaryExpression(int a, int b, char op) 来计算 a op b 的值;主函数首先do{}while(next_permutation)以获得所有的全排列过程,对于每个排列a, b, c, d,对于每一种加括号方式按照括号优先级计算表达式的值,判断是否等于24, 如果等于,直接return,否则,判断下一种加括号的方式。

注意:对于op == '/', a / b 时,需要保证 b != 0 && a % b == 0。如果不满足该条件,则直接进行下一轮循环。

程序源码

  1 #include <iostream>

  2 #include <string>

  3 #include <vector>

  4 #include <algorithm>

  5 #include <functional>

  6 #include <cstdio>

  7 #include <cstdlib>

  8 #include <cassert>

  9 using namespace std;

 10 

 11 // given number a, b and operator ch, return eval(a ch b)

 12 int calculateBinaryExpression(int a, int b, char ch)

 13 {

 14     switch(ch)

 15     {

 16     case '+':

 17         return a + b;

 18         break;

 19     case '-':

 20         return a - b;

 21         break;

 22     case '*':

 23         return a * b;

 24         break;

 25     case '/':

 26         assert(b != 0);

 27         return a / b;

 28         break;

 29     default:

 30         cerr << "WRONG OPERATOR !" << endl;

 31         return -1;

 32         break;

 33     }

 34 }

 35 

 36 // Make 24 game

 37 // BASIC IDEA: permutation all the possible cases: A(4, 4) = 24;

 38 //             Need 3 operators: 4 * 4 * 4 = 64;

 39 //             All five possible adding parenthese:

 40 //             (1) (A @ B) @ (C @ D)

 41 //             (2) (A @ (B @ C) ) @ D

 42 //             (3) ( (A @ B) @ C) @ D

 43 //             (4) A @ ( ( B @ C) @ D)

 44 //             (5) A @ ( B @ (C @ D) )

 45 //             Total Possible cases: 24 * 64 * 5 = 7680, Brute Force 

 46 // Input:  4 numbers in [1, 13], 

 47 //         use '+','-','*','/' and '(',')' to make 24

 48 // Output: If it is possible to make 24, output the expression

 49 //         Else return -1;

 50 // Notice: When calcalute x / y, need to assert (y != 0 && x % y == 0)

 51 //         If Not, continue

 52 string make24(int num1, int num2, int num3, int num4)

 53 {

 54     vector<int> v(4, 0);

 55     v[0] = num1; v[1] = num2; v[2] = num3; v[3] = num4;

 56     sort(v.begin(), v.end());

 57 

 58     string ops("+-*/");

 59 

 60     do 

 61     {

 62         // The first parenthesis

 63         // (A @ B) @ (C @ D)

 64         for (size_t i = 0; i < ops.size(); ++i)

 65         {

 66             // A @ B

 67             char op1 = ops[i];

 68             if (op1 == '/' && (v[1] == 0 || v[0] % v[1] != 0)) continue;

 69             int ans1 = calculateBinaryExpression(v[0], v[1], op1);

 70             for (size_t j = 0; j < ops.size(); ++j)

 71             {

 72                 // C @ D

 73                 char op2 = ops[j];

 74                 if (op2 == '/' && (v[3] == 0 || v[2] % v[3] != 0)) continue;

 75                 int ans2 = calculateBinaryExpression(v[2], v[3], op2);

 76 

 77                 for (size_t k = 0; k < ops.size(); ++k)

 78                 {

 79                     // (A @ B) @ (C @ D)

 80                     char op3 = ops[k];

 81                     if (op3 == '/' && (ans2 == 0 || ans1 % ans2 != 0)) continue;

 82                     int ans = calculateBinaryExpression(ans1, ans2, op3);

 83                     if (ans == 24)

 84                     {

 85                         string str;

 86                         str.push_back('(');

 87                         str += to_string((long long)(v[0]));

 88                         str.push_back(op1);

 89                         str += to_string((long long)(v[1]));

 90                         str.push_back(')');

 91                         str.push_back(op3);

 92                         str.push_back('(');

 93                         str += to_string((long long)(v[2]));

 94                         str.push_back(op2);

 95                         str += to_string((long long)(v[3]));

 96                         str.push_back(')');

 97                         return str;

 98                     }

 99                 }

100             }

101             

102         }

103 

104         // The second parethesis

105         // (A op2 (B op1 C)) op3 D

106         for (size_t i = 0; i < ops.size(); ++i)

107         {

108             char op1 = ops[i];

109             if (op1 == '/' && (v[2] == 0 || v[1] % v[2] != 0)) continue;

110             int ans1 = calculateBinaryExpression(v[1], v[2], op1);

111             for (size_t j = 0; j < ops.size(); ++j)

112             {

113                 char op2 = ops[j];

114                 if (op2 == '/' && (ans1 == 0 || v[0] % ans1 != 0)) continue;

115                 int ans2 = calculateBinaryExpression(v[0], ans1, op2);

116                 for (size_t k = 0; k < ops.size(); ++k)

117                 {

118                     char op3 = ops[k];

119                     if (op3 == '/' && (v[3] == 0 || ans2 % v[3] != 0)) continue;

120                     int ans = calculateBinaryExpression(ans2, v[3], op3);

121                     if (ans == 24)

122                     {

123                         string str;

124                         str.push_back('(');

125                         str += to_string((long long)v[0]);

126                         str.push_back(op2);

127                         str.push_back('(');

128                         str += to_string((long long)v[1]);

129                         str.push_back(op1);

130                         str += to_string((long long)v[2]);

131                         str.push_back(')');

132                         str.push_back(')');

133                         str.push_back(op3);

134                         str += to_string((long long)v[3]);

135                         return str;

136                     }

137                 }

138             }

139         }

140 

141         // The third parentheses

142         // ( ( A op1 B) op2 C) op3 D

143         for (size_t i = 0; i < ops.size(); ++i)

144         {

145             char op1 = ops[i];

146             if (op1 == '/' && (v[1] == 0 || v[0] % v[1] != 0)) continue;

147             int ans1 = calculateBinaryExpression(v[0], v[1], op1);

148             for (size_t j = 0; j < ops.size(); ++j)

149             {

150                 char op2 = ops[j];

151                 if (op2 == '/' && (v[2] == 0 || ans1 % v[2] != 0)) continue;

152                 int ans2 = calculateBinaryExpression(ans1, v[2], op2);

153                 for (size_t k = 0; k < ops.size(); ++k)

154                 {

155                     char op3 = ops[k];

156                     if (op3 == '/' && (v[3] == 0 || ans2 % v[3] != 0)) continue;

157                     int ans = calculateBinaryExpression(ans2, v[3], op3);

158                     if (ans == 24)

159                     {

160                         string str("((");

161                         str += to_string((long long)v[0]);

162                         str.push_back(op1);

163                         str += to_string((long long)v[1]);

164                         str.push_back(')');

165                         str.push_back(op2);

166                         str += to_string((long long)v[2]);

167                         str.push_back(')');

168                         str.push_back(op3);

169                         str += to_string((long long)v[4]);

170                         return str;

171                     }

172                 }

173             }

174         }

175 

176         // The fourth parentheses

177         // A op3 ( ( B op1 C ) op2 D)

178         for (size_t i = 0; i < ops.size(); ++i)

179         {

180             char op1 = ops[i];

181             if (op1 == '/' && (v[2] == 0 || v[1] % v[2] != 0)) continue;

182             int ans1 = calculateBinaryExpression(v[1], v[2], op1);

183             for (size_t j = 0; j < ops.size(); ++j)

184             {

185                 char op2 = ops[j];

186                 if (op2 == '/' && (v[3] == 0 || ans1 % v[3] != 0)) continue;

187                 int ans2 = calculateBinaryExpression(ans1, v[3], op2);

188                 for (size_t k = 0; k < ops.size(); ++k)

189                 {

190                     char op3 = ops[k];

191                     if (op3 == '/' && (ans2 == 0 || v[0] % ans2 != 0)) continue;

192                     int ans = calculateBinaryExpression(v[0], ans2, op3);

193                     if (ans == 24)

194                     {

195                         string str;

196                         str += to_string((long long)v[0]);

197                         str.push_back(op3);

198                         str += "((";

199                         str += to_string((long long)v[1]);

200                         str.push_back(op1);

201                         str += to_string((long long)v[2]);

202                         str.push_back(')');

203                         str.push_back(op2);

204                         str += to_string((long long)v[3]);

205                         str.push_back(')');

206                         return str;

207                     }

208                 }

209             }

210         }

211         

212         // The fifth parenthese

213         // A op3 ( B op2 ( C op1 D) );

214         for (size_t i = 0; i < ops.size(); ++i)

215         {

216             char op1 = ops[i];

217             if (op1 == '/' && (v[3] == 0 || v[2] % v[3] != 0)) continue;

218             int ans1 = calculateBinaryExpression(v[2], v[3], op1);

219             for (size_t j = 0; j < ops.size(); ++j)

220             {

221                 char op2 = ops[j];

222                 if (op2 == '/' && (ans1 == 0 || v[1] % ans1 != 0)) continue;

223                 int ans2 = calculateBinaryExpression(v[1], ans1, op2);

224                 for (size_t k = 0; k < ops.size(); ++k)

225                 {

226                     char op3 = ops[k];

227                     if (op3 == '/' && (ans2 == 0 || v[0] % ans2 != 0)) continue;

228                     int ans = calculateBinaryExpression(v[0], ans2, op3);

229                     if (ans == 24)

230                     {

231                         string str;

232                         str += to_string((long long)v[0]);

233                         str.push_back(op3);

234                         str.push_back('(');

235                         str += to_string((long long)v[1]);

236                         str.push_back(op2);

237                         str.push_back('(');

238                         str += to_string((long long)v[2]);

239                         str.push_back(op1);

240                         str += to_string((long long)v[3]);

241                         str += "))";

242                         return str;

243                     }

244                 }

245             }

246         }

247 

248     } while(next_permutation(v.begin(), v.end()));

249 

250     return "-1";

251 }

252 

253 int main()

254 {

255     int a, b, c, d;

256     cin >> a >> b >> c >> d;

257     string ans = make24(a, b, c, d);

258     cout << ans << endl;

259     return 0;

260 }

 参考文献

[1] 速算24算法思路

[2] 24 Game/Countdown/Number Game solver, but without parentheses in the answer


你可能感兴趣的:(算法)