poj 2288 Islands and Bridges
题意:
定义一个最优哈密顿回路如果把如下描述的值最大化:
有n个城市。一个哈密顿回路C1C2..Cn的值由3个部分组成:
1.这个路径上每个岛的值Vi之和;
2.这个路径上每条边Vi*Vi+1之和;
3.如果路径上连续的三个岛屿CiCi+1Ci+2之间两两互相连通,那么就加上Vi*Vi+1*Vi+2。
求出最优哈密顿回路的值以及个数。
(一条路径及其反转,认为是同一条路径)。
思路:
首先,计算值肯定是跟前两个岛有关系的,此时就可以用当前状态为S,前两个岛为i,前一个岛为j来进行状态的转移。
dp[S|(1<<k)][j][k] = max(dp[S|(1<<k)][j][k],dp[S][i][j] + v[k] + v[j]*v[k] + v[j]*v[k]*v[i]),最后一个部分必须满足两两互相连通才能加。
如果dp[S|(1<<k)][j][k]已经有值并且与当前计算出来的值相同,路径条数直接加上即可。
最后路径条数要减半,因为逆序的路径也是计算了的。
注意dp数组的初始化。
代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 const int N = 14; 6 int dp[1<<N][N][N]; 7 long long num[1<<N][N][N]; 8 int v[N]; 9 bool mp[N][N]; 10 int main() 11 { 12 int t; 13 scanf("%d",&t); 14 while (t--) 15 { 16 int n,m; 17 scanf("%d%d",&n,&m); 18 memset(mp,0,sizeof(mp)); 19 memset(dp,-1,sizeof(dp)); 20 memset(num,0,sizeof(num)); 21 for (int i = 0;i < n;i++) scanf("%d",&v[i]); 22 for (int i = 0;i < m;i++) 23 { 24 int x,y; 25 scanf("%d%d",&x,&y); 26 x--,y--; 27 mp[x][y] = mp[y][x] = 1; 28 } 29 if (n == 1) 30 { 31 printf("%d 1\n",v[0]); 32 continue; 33 } 34 for (int i = 0;i < n;i++) 35 { 36 for (int j = 0;j < n;j++) 37 { 38 if (i == j) continue; 39 if (!mp[i][j]) continue; 40 dp[(1<<i)|(1<<j)][i][j] = v[i] + v[j] + v[i]*v[j]; 41 num[(1<<i)|(1<<j)][i][j] = 1; 42 } 43 } 44 for (int i = 0;i < (1<<n);i++) 45 { 46 for (int j = 0;j < n;j++) 47 { 48 for (int k = 0;k < n;k++) 49 { 50 if (j == k) continue; 51 if (!mp[j][k]) continue; 52 if (dp[i][j][k] < 0) continue; 53 for (int l = 0;l < n;l++) 54 { 55 if (i&(1<<l)) continue; 56 if (!mp[k][l]) continue; 57 int tmp = v[l] + v[k] * v[l]; 58 if (mp[j][k] && mp[j][l] && mp[l][k]) 59 { 60 tmp += v[j]*v[k]*v[l]; 61 } 62 if (dp[i|(1<<l)][k][l] < dp[i][j][k] + tmp) 63 { 64 dp[i|(1<<l)][k][l] = dp[i][j][k] + tmp; 65 num[i|(1<<l)][k][l] = num[i][j][k]; 66 } 67 else if (dp[i|(1<<l)][k][l] == dp[i][j][k] + tmp) 68 { 69 num[i|(1<<l)][k][l] += num[i][j][k]; 70 } 71 } 72 } 73 } 74 } 75 int maxn = -1; 76 long long cnt = 0; 77 for (int i = 0;i < n;i++) 78 { 79 for (int j = 0;j < n;j++) 80 { 81 if (i == j) continue; 82 maxn = max(dp[(1<<n)-1][i][j],maxn); 83 } 84 } 85 if (maxn == -1) printf("0 0\n"); 86 else 87 { 88 for (int i = 0;i < n;i++) 89 { 90 for (int j = 0;j < n;j++) 91 { 92 if (i == j) continue; 93 if (dp[(1<<n)-1][i][j] == maxn) cnt += num[(1<<n)-1][i][j]; 94 } 95 } 96 printf("%d %lld\n",maxn,cnt/2); 97 } 98 } 99 return 0; 100 }
康复训练中~欢迎交流!