POJ2288 Islands and bridges 【狀態壓縮,計數】
阿新 • • 發佈:2020-10-08
分成兩問。第一問求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}\n", _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!\n", 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}\n", _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\n", 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\n", 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; } } }