zoukankan      html  css  js  c++  java
  • POJ2288 Islands and bridges 【状态压缩,计数】

    分成两问。第一问求Hamilton路径最大赋值,第二问求值最大的hamilton路径有多少个。使用状态压缩来记录状态简化转移。

    把细节关注好是重点。本题代码比较繁琐,一定要养成良好的代码习惯,避免出现奇怪的bug。

    第一份代码,用bfs实现记忆化搜索。

    #include <queue>
    #include <cstdio>
    #include <cstdlib>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    #define int long long
    
    const int N = 14;
    const int INF = 0x3f3f3f3f3f3f3f3f;
    
    
    int T, n, m, val[N], res[N][N][1 << N], cnt[N][N][1 << N];
    
    bool G[N][N];
    
    void Init () {
        for (int i = 0; i < N; ++i) {
            for (int j = 0; j < N; ++j) {
                G[i][j] = 0;
                for (int k = 0; k < (1 << N); ++k) {
                    res[i][j][k] = -INF;
                    cnt[i][j][k] = 0;
                }
            }
        }
    }
    
    struct Node {
        int cur, pre, sit;
    };
    
    queue <Node> que;
    
    signed main () {
        // freopen ("data.in", "r", stdin);
        cin >> T;
        while (T--) {
            Init ();
            cin >> n >> m;
            for (int i = 1; i <= n; ++i) {
                cin >> val[i];
            }
            for (int i = 1; i <= m; ++i) {
                int u, v;
                cin >> u >> v;
                G[u][v] = G[v][u] = true;
            }
            if (n == 1) {
                cout << val[1] << " 1" << endl;
                continue;
            }
            for (int i = 1; i <= n; ++i) {
                res[i][0][1 << (i - 1)] = 0;
                cnt[i][0][1 << (i - 1)] = 1;
                que.push ((Node) {i, 0, 1 << (i - 1)}); 
            }
            while (!que.empty ()) {
                Node _node = que.front ();
                que.pop ();
                // printf ("Node now: {cur = %d, pre = %d, sit = %d, res = %d}
    ", _node.cur, _node.pre, _node.sit, res[_node.cur][_node.pre][_node.sit]);
                for (int i = 1; i <= n; ++i) {
                    if (G[_node.cur][i] == false) {
                        continue;
                    }
                    if ((_node.sit & (1 << (i - 1))) == 0) {
                        // printf ("%d : yes!
    ", i);
                        // 第二位尚未到达
                        int _newres = res[_node.cur][_node.pre][_node.sit] + val[_node.cur] * val[i];
                        if (G[i][_node.pre]) {
                            _newres += val[_node.pre] * val[_node.cur] * val[i];
                        } 
                        int _newcur = i;
                        int _newpre = _node.cur;
                        int _newsit = _node.sit | (1 << (i - 1));
                        // printf ("Node next: {cur = %d, pre = %d, sit = %d, res = %d}
    ", _newcur, _newpre, _newsit, _newres);
                        if (_newres > res[_newcur][_newpre][_newsit]) {
                            cnt[_newcur][_newpre][_newsit] = cnt[_node.cur][_node.pre][_node.sit];
                            // printf ("cnt next = %d
    ", cnt[_newcur][_newpre][_newsit]);
                            if (res[_newcur][_newpre][_newsit] < 0) {
                                que.push ((Node) {_newcur, _newpre, _newsit});
                            }
                            res[_newcur][_newpre][_newsit] = _newres;
                        } else if (_newres == res[_newcur][_newpre][_newsit]) {
                            // printf ("cnt next += %d
    ", cnt[_node.cur][_node.pre][_node.sit]);
                            cnt[_newcur][_newpre][_newsit] += cnt[_node.cur][_node.pre][_node.sit];
                        }
                    }
                }
            }
            int ans1 = -INF, ans2 = 0, sum = 0;
            for (int i = 1; i <= n; ++i) {
                sum += val[i];
                for (int j = 1; j <= n; ++j) {
                    if (ans1 < res[i][j][(1 << n) - 1]) {
                        ans1 = res[i][j][(1 << n) - 1];
                        ans2 = cnt[i][j][(1 << n) - 1];
                    } else if (ans1 == res[i][j][(1 << n) - 1]) {
                        ans2 += cnt[i][j][(1 << n) - 1];
                    }
                    // cout << ans2 << endl;
                }
            }
            if (ans1 < 0) {
                cout << "0 0" << endl;
            } else {
                cout << ans1 + sum << " " << ans2 / 2 << endl;
            }
        }
    }
    

    第二份代码,使用循环的形式。

    #include <queue>
    #include <cstdio>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    #define int long long
    
    const int N = 14;
    const int INF = 0x3f3f3f3f3f3f3f3f;
    
    
    int T, n, m, val[N], res[N][N][1 << N], cnt[N][N][1 << N];
    
    bool G[N][N];
    
    void Init () {
        for (int i = 0; i < N; ++i) {
            for (int j = 0; j < N; ++j) {
                G[i][j] = false;
                for (int k = 0; k < (1 << N); ++k) {
                    res[i][j][k] = -INF;
                    cnt[i][j][k] = 0;
                }
            }
        }
    }
    
    signed main () {
        cin >> T;
        while (T--) {
            Init ();
            cin >> n >> m;
            for (int i = 1; i <= n; ++i) {
                cin >> val[i];
            }
            for (int i = 1; i <= m; ++i) {
                int u, v;
                cin >> u >> v;
                G[u][v] = G[v][u] = true;
            }
            if (n == 1) {
                cout << val[1] << " 1" << endl;
                continue;
            }
            for (int i = 1; i <= n; ++i) {
                for (int j = 1; j <= n; ++j) {
                    if (i == j || !G[i][j]) {
                        continue;
                    }
                    int s1 = 1 << (i - 1);
                    int s2 = 1 << (j - 1);
                    res[i][j][s1 ^ s2] = val[i] * val[j];
                    cnt[i][j][s1 ^ s2] = 1;
                }
            }
            for (int sit = 0; sit < 1 << n; ++sit) {
                for (int u = 1; u <= n; ++u) {
                    int s1 = 1 << (u - 1);
                    if (!sit & s1) continue;
                    for (int v = 1; v <= n; ++v) {
                        int s2 = 1 << (v - 1);
                        if (u == v || (!G[u][v]) || (!(sit & s2)) || res[v][u][sit] == -INF) continue;
                        for (int t = 1; t <= n; ++t) {
                            int s3 = 1 << (t - 1);
                            if (t == u || t == v || (sit & s3) || !G[v][t]) continue;
                            int sum = val[v] * val[t];
                            if (G[u][t]) {
                                sum += val[u] * val[v] * val[t];
                            }
                            if (res[v][u][sit] + sum > res[t][v][sit ^ s3]) {
                                res[t][v][sit ^ s3] = res[v][u][sit] + sum;
                                cnt[t][v][sit ^ s3] = cnt[v][u][sit];
                            } else if (res[v][u][sit] + sum == res[t][v][sit ^ s3]) {
                                cnt[t][v][sit ^ s3] += cnt[v][u][sit];
                            }
                        }
                    }
                }
            }
            int ans1 = -INF, ans2 = 0, sum = 0;;
            for (int i = 1; i <= n; ++i) {
                sum += val[i];
                for (int j = 1; j <= n; ++j) {
                    if (ans1 < res[i][j][(1 << n) - 1]) {
                        ans1 = res[i][j][(1 << n) - 1];
                        ans2 = cnt[i][j][(1 << n) - 1];
                    } else if (ans1 == res[i][j][(1 << n) - 1]) {
                        ans2 += cnt[i][j][(1 << n) - 1];
                    }
                }
            }
            if (ans1 < 0) {
                cout << "0 0" << endl;
            } else {
                cout << ans1 + sum << " " << ans2 / 2 << endl;
            }
        }
    }
    
  • 相关阅读:
    csuOJ啊 1553
    Codeforces 111B【看看自己和别人在代码能力上的差距!】
    hdu1849
    hdu 1847
    校队训练赛,同时也是HDU4497(数论:素数分解+组合数学)
    POJ 2356 (抽屉原理)
    线段树总结一【转】
    训练赛(1---5)D
    训练赛(1---5)A
    HDU1556 【树状数组】(改段求点)
  • 原文地址:https://www.cnblogs.com/maomao9173/p/13781476.html
Copyright © 2011-2022 走看看