POJ-2288 状压dp Hamilton回路
题意:Hamilton回路的权值为:
1、经过的每条边的两个点的点权和
2、连续经过两点的乘积
3、如果三条边形成三角形则再加上三个点权的乘积
求最大值+路径条数
思路:10来个点用一个小的邻接矩阵就可以判断是否相连,判断三角形就可以在dp加一维记录前两个点的信息,枚举的时候多枚举到前2个点
即dp[state][pre][now],表示当前为state、前一个点pre、当前点now的最大权值,路径条数跟最短路条数的记录方法一样
错的地方:没判断dp[state][pre][now] == -1就WA了,加上就A了,我之前明明都加上了i & (1<<j)这类点与状态冲突的判断,原因我猜是初始化+刷表法,-1是不合法不存在的状态,没加上会导致后面别的状态被刷了
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <queue> 6 #include <vector> 7 #define LL long long 8 #define INF 0x3f3f3f3f 9 #define debug(x) cout << #x << " = " << x << endl 10 using namespace std; 11 12 LL dp[1<<13][14][14], num[1<<13][14][14]; 13 LL a[14]; 14 bool d[14][14]; 15 16 int main() { 17 int t, n, m; 18 scanf("%d", &t); 19 while (t--){ 20 scanf("%d%d", &n, &m); 21 memset(d, 0, sizeof d); 22 for (int i = 0; i < n; i++) scanf("%lld", &a[i]); 23 for (int i = 0; i < m; i++){ 24 int u, v; 25 scanf("%d%d", &u, &v); 26 u--, v--; 27 d[u][v] = d[v][u] = 1; 28 } 29 if (n == 1){ 30 printf("%lld 1\n", a[0]); 31 continue; 32 } 33 memset(dp, -1, sizeof dp); 34 memset(num, 0, sizeof num); 35 for (int i = 0; i < n; i++){ 36 for (int j = 0; j < n; j++){ 37 if (!d[i][j]) continue; 38 if (i == j) continue; 39 dp[(1<<i)+(1<<j)][i][j] = a[i]+a[j]+a[i]*a[j]; 40 num[(1<<i)+(1<<j)][i][j] = 1; 41 } 42 } 43 //dp[state][pre][now] 44 for (int i = 3; i < (1<<n); i++){ 45 for (int j = 0; j < n; j++){ 46 if (!(i & (1 << j))) continue; 47 for (int k = 0; k < n; k++){ 48 if (!(i & (1 << k))) continue; 49 if (!d[j][k]) continue; 50 if (dp[i][j][k] == -1) continue; 51 for (int r = 0; r < n; r++){ 52 if (i & (1 << r)) continue; 53 if (!d[k][r]) continue; 54 LL tmp = dp[i][j][k] + a[r] + a[k]*a[r]; 55 if (d[j][r]) tmp += a[j]*a[k]*a[r]; 56 int nxt = i + (1 << r); 57 if (tmp > dp[nxt][k][r]){ 58 dp[nxt][k][r] = tmp; 59 num[nxt][k][r] = num[i][j][k]; 60 } 61 else if (tmp == dp[nxt][k][r]) 62 num[nxt][k][r] += num[i][j][k]; 63 } 64 } 65 } 66 } 67 LL ans = -1, sum = 0; 68 for (int i = 0; i < n; i++){ 69 for (int j = 0; j < n; j++){ 70 if (i == j) continue; 71 if (!d[i][j]) continue; 72 if (dp[(1<<n)-1][i][j] > ans){ 73 ans = dp[(1<<n)-1][i][j]; 74 sum = num[(1<<n)-1][i][j]; 75 } 76 else if (ans == dp[(1<<n)-1][i][j]) 77 sum += num[(1<<n)-1][i][j]; 78 } 79 } 80 if (ans == -1) printf("0 0\n"); 81 else printf("%lld %lld\n", ans, sum/2); 82 } 83 return 0; 84 }