题意:
给你一张地图,上面有一些岛和桥。你要求出最大的三角哈密顿路径,以及他们的数量。
哈密顿路:一条经过所有岛的路径,每个岛只经过一次。
最大三角哈密顿路:满足价值最大的哈密顿路。
价值计算分为以下三部分:
1. 所有点权的和。
2. 对于路径上任意两个连续的点(共享一条边)的点权乘积的和。
3. 对于路径上任意三个连续的点,如果他们构成一个三角形(两两之间有边),那么加上三点点权的乘积
思路:
状态压缩动态规划, dp[st][i][j] 表示状态是st, 前一步在i,现在停在j的最大价值。
cnt[st][i][j] 表示计数。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 using namespace std; 6 7 typedef __int64 ll; 8 9 const int MAXN= 13; 10 11 ll dp[1<<13][MAXN][MAXN]; 12 ll cnt[1<<13][MAXN][MAXN]; 13 14 int G[20][20]; 15 ll val[20]; 16 int n, m; 17 18 void print() { 19 for (int i = 0; i <= n; i++) { 20 for (int j = 0; j <= n; j++) 21 printf("%d ", G[i][j]); 22 puts(""); 23 } 24 } 25 26 int main() { 27 #ifdef Phantom01 28 freopen("PKU2288.txt", "r", stdin); 29 #endif // Phantom01 30 31 int T; 32 scanf("%d", &T); 33 while (T--) { 34 scanf("%d%d", &n, &m); 35 memset(dp, 0, sizeof(dp)); 36 memset(cnt, 0, sizeof(cnt)); 37 memset(G, 0, sizeof(G)); 38 for (int i = 0; i < n; i++) { 39 scanf("%I64d", &val[i]); 40 } 41 for (int i = 0; i < m; i++) { 42 int u, v; 43 scanf("%d%d", &u, &v); 44 G[u-1][v-1] += 1; 45 G[v-1][u-1] += 1; 46 } 47 //print(); 48 if (1==n) { 49 printf("%I64d 1 ", val[0]); 50 continue; 51 } 52 53 for (int i = 0; i < n; i++) 54 for (int j = 0; j < n; j++) if (G[i][j]){ 55 dp[(1<<i)|(1<<j)][i][j] = val[i] + val[j] + val[i]*val[j]; 56 cnt[(1<<i)|(1<<j)][i][j] += G[i][j]; 57 } 58 59 for (int i = 1; i < (1<<n)-1; i++) 60 for (int j = 0; j < n; j++) if (i&(1<<j)) 61 for (int u = 0; u < n; u++) if ((i&(1<<u)) && (j!=u) && cnt[i][j][u]) 62 for (int v = 0; v < n; v++) if (G[u][v] && !(i&(1<<v))) { 63 ll &now = dp[i][j][u]; 64 ll &next = dp[i|(1<<v)][u][v]; 65 ll va = val[v]*(1 + val[u]); 66 if (G[j][v]) va += val[j]*val[u]*val[v]; 67 if (next < now+va) { 68 next = now+va; 69 cnt[i|(1<<v)][u][v] = cnt[i][j][u]; 70 } else if (next==now+va) 71 cnt[i|(1<<v)][u][v] += cnt[i][j][u]; 72 } 73 74 ll ans = 0, c = 0; 75 for (int i = 0; i < n; i++) 76 for (int j = 0; j < n; j++) 77 if (ans<dp[(1<<n)-1][i][j]) { 78 ans = dp[(1<<n)-1][i][j]; 79 c = cnt[(1<<n)-1][i][j]; 80 } else if (ans==dp[(1<<n)-1][i][j]) 81 c += cnt[(1<<n)-1][i][j]; 82 83 printf("%I64d %I64d ", ans, c/2); 84 } 85 86 return 0; 87 }
P.s.: 开始多开了一维导致MLE,后来发现读错题了 0 0 结果花了一晚上