24点
随便写点24点游戏求解程序。两种解法。通过Live Writer 投递,再次测试。编程之美1.16节。
关于最后一个扩展问题:引入阶乘运算。对于DP实现,这个不会成为问题。但是,对于深搜,由于阶乘运算不会减少集合的基数,需要进行减枝。
其中的一种策略是,当集合中最大的数字除去所有余下的数仍然大于24的话,就可以不必继续了。
公共代码:
struct Expr {
double r; string e; Expr(double rr = 0, const string& ee = ""): r(rr), e(ee) {} bool operator<(const Expr& other) const { return r < other.r || r == other.r && e < other.e; } bool operator==(const Expr& other) const { return !(*this < other) && !(other < *this); } }; string int2card(int i) { if (i < 10 && i > 1) return string(1, '0' + i); else if (i == 10) return "10"; else if (i == 11) return "J"; else if (i == 12) return "Q"; else if (i == 13) return "K"; return "A"; }
深搜求解:
vector<string> exprs;
void dfs(const vector<int>& vec) { vector<Expr> e; for (size_t i = 0; i < vec.size(); ++i) e.push_back(Expr(vec[i], int2card(vec[i]))); dfs(e); } int main() { vector<int> vec(4); while (cin>>vec[0]>>vec[1]>>vec[2]>>vec[3]) { exprs.clear(); dfs(vec); if (exprs.size()) { sort(exprs.begin(), exprs.end()); exprs.erase(unique(exprs.begin(), exprs.end()), exprs.end()); for (size_t i = 0; i < exprs.size(); ++i) cout<<exprs[i]<<'\n'; } else { cout<<"No solution.\n"; } } return 0; }void dfs(const vector<Expr>& e) { if (e.size() == 1) { if (abs(e[0].r - 24) < 0.000001) exprs.push_back(e[0].e); } for (size_t i = 0; i < e.size(); ++i) { for (size_t j = i+1; j < e.size(); ++j) { vector<Expr> ne; for (size_t p = 0; p < e.size(); ++p) { if (p != i && p != j) ne.push_back(e[p]); } ne.push_back(Expr(e[i].r + e[j].r, "(" + e[i].e + "+" + e[j].e + ")")); dfs(ne); ne.pop_back(); ne.push_back(Expr(e[i].r * e[j].r, e[i].e + "*" + e[j].e)); dfs(ne); ne.pop_back(); ne.push_back(Expr(e[i].r - e[j].r, "(" + e[i].e + "-" + e[j].e + ")")); dfs(ne); ne.pop_back(); ne.push_back(Expr(e[j].r - e[i].r, "(" + e[j].e + "-" + e[i].e + ")")); dfs(ne); ne.pop_back(); if (e[i].r) { ne.push_back(Expr(e[j].r / e[i].r, e[j].e + "/" + e[i].e)); dfs(ne); ne.pop_back(); } if (e[j].r) { ne.push_back(Expr(e[i].r / e[j].r, e[i].e + "/" + e[j].e)); dfs(ne); ne.pop_back(); } } } }
动态规划:
void calc(const vector<int>& vec, vector<string>& exprs) { int nset = (int)pow(2.0, (int)vec.size()); vector< vector<Expr> > subset(nset, vector<Expr>()); for (size_t i = 0; i < vec.size(); ++i) subset[(size_t)pow(2.0, (int)i)].push_back(Expr(vec[i], int2card(vec[i]))); for (int i = 3; i < nset; ++i) { if (subset[i].size()) continue; for (int k = 1; k <= i/2; ++k) { if ((k&i) != k) continue; for (size_t p = 0; p < subset[k].size(); ++p) { Expr& a = subset[k][p]; for (size_t q = 0; q < subset[i-k].size(); ++q) { Expr& b = subset[i-k][q]; subset[i].push_back(Expr(a.r+b.r, "(" + a.e + "+" + b.e + ")")); subset[i].push_back(Expr(a.r*b.r, a.e + "*" + b.e)); subset[i].push_back(Expr(a.r-b.r, "(" + a.e + "-" + b.e + ")")); subset[i].push_back(Expr(b.r-a.r, "(" + b.e + "-" + a.e + ")")); if (b.r) subset[i].push_back(Expr(a.r/b.r, a.e + "/" + b.e)); if (a.r) subset[i].push_back(Expr(b.r/a.r, b.e + "/" + a.e)); } } } sort(subset[i].begin(), subset[i].end()); subset[i].erase(unique(subset[i].begin(), subset[i].end()), subset[i].end()); } for (vector<Expr>::iterator it = subset[nset-1].begin(); it != subset[nset-1].end(); ++it) if (abs(it->r - 24.0) < 0.00001) exprs.push_back(it->e); } int main() { vector<int> vec(4); while (cin>>vec[0]>>vec[1]>>vec[2]>>vec[3]) { vector<string> exprs; calc(vec, exprs); if (exprs.size()) { for (size_t i = 0; i < exprs.size(); ++i) cout<<exprs[i]<<'\n'; } else cout<<"No solution\n"; } return 0; }