问题:
解法二:
给玩家4张牌,每张牌的面值在1-13之间,允许其中有数值相同的牌,采用加、减、乘、除四则运算,允许中间运算存在小数,并且可以使用括号,但每张牌只能用一次。构造表达式,使其结果为24.
解法一:
利用递归,强搜!
代码如下:
#include <iostream>
#include <string>
#include <cmath>
using namespace std;
const double Threshold = 1E-6;
const int CardsNumber = 4;
const int ResultValue = 24;
double number[CardsNumber];
string result[CardsNumber];
bool pointsGame(int n) {
if(1 == n) {
if(fabs(number[0] - ResultValue) < Threshold) {
cout << result[0] << endl;
return true;
}else return false;
}
for(int i = 0; i < n; ++i) {
for(int j = i + 1; j < n; ++j) {
double a, b;
string expa, expb;
a = number[i];
b = number[j];
number[j] = number[n - 1];
expa = result[i];
expb = result[j];
result[j] = result[n - 1];
number[i] = a + b;
result[i] = '(' + expa + '+' + expb + ')';
if(pointsGame(n - 1)) return true;
number[i] = a - b;
result[i] = '(' + expa + '-' + expb + ')';
if(pointsGame(n - 1)) return true;
number[i] = b - a;
result[i] = '(' + expb + '-' + expa + ')';
if(pointsGame(n - 1)) return true;
number[i] = a * b;
result[i] = '(' + expa + '*' + expb + ')';
if(pointsGame(n - 1)) return true;
if(b != 0) {
number[i] = a / b;
result[i] = '(' + expa + '/' + expb + ')';
if(pointsGame(n - 1)) return true;
}
if(a != 0) {
number[i] = b / a;
result[i] = '(' + expb + '/' + expa + ')';
if(pointsGame(n - 1)) return true;
}
number[i] = a;
number[j] = b;
result[i] = expa;
result[j] = expb;
}
}
return false;
}
int main() {
int x;
for(int i = 0; i < CardsNumber; ++i) {
cin >> x;
number[i] = x;
char buffer[20];
itoa(x, buffer, 10);
result[i] = buffer;
}
if(pointsGame(CardsNumber)) cout << "successed" << endl;
else cout << "Failed" << endl;
return 0;
}
解法二:
利用书中讲的递归的方法,f(A)为对集合A中的元素进行所有可能的四则混合运算所得到的值。
Fork(A, B)代表对A, B中的元素进行四则运算的结果。
在下面的代码中,用二进制来代表一个集合,全集为1111,意思就是这个集合里面有4个数字。以此类推
伪代码:
24Game(Array) { //Array为初始输入的集合,其中的元素表示为
for(int i = 1; i <= 2deNcifang - 1; ++i) S[i] = kongji; //初始化将S中的各个集合置为空集
for(int i = 0; i < n; ++i) S[2deIcifang] = {ai}; //先对每个只有一个元素的真子集赋值,既为该元素本身
for(int i = 1; i <= 2deNcifang - 1; ++i) S[i] = f(i);
Check(S[2deNcifang-1]);
}
f(int i) {
if(S[i] != kongji) return S[i];
for(int x = 1; x < i; ++x) //只有小于i的x才可能称为i的真子集
if(x & i == x) //&为与运算,只有当括号内的表达式成立的时候,x才为i的子集,
S[i] U= Fork(f(x), f(i-x)); //这里的U为并运算,在Fork的过程中,要去除中间结果
}