画圆的沙滩

亦简亦美

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<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 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 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;
}

posted on 2011-03-11 16:10  acmaru  阅读(284)  评论(0编辑  收藏  举报

导航