poj 2288 Islands and Bridges解题报告-状态压缩dp
题目链接:http://poj.org/problem?id=2288
题目描述:哈密尔顿路问题。n个点,每一个点有权值,设哈密尔顿路为 C1C2...Cn,Ci的权值为Vi,一条哈密尔顿路的值分为三部分计算:
1.每一个点的权值之和
2.对于图中的每一条CiCi+1,加上Vi*Vi+1
3.对于路径中的连续三个点:CiCi+1Ci+2,若在图中,三点构成三角形,则要加上Vi*Vi+1*Vi+2
求一条汉密尔顿路可以获得的最大值,并且还要输出有多少条这样的哈密尔顿路。
这道题的状态感觉不是很难想,因为根据一般的哈密尔顿路问题,首先想到的是设计二维状态,dp[i , s]表示当前在i点,走过的点形成状态集合s。但是这道题在求解值的时候有一个不一样的地方,就是第三部分,如果还是设计成二维的状态,就会很麻烦,因为每加入一个新点,要判断新点、当前点、倒数第二个点是否构成三角形,所以要记录倒数第二个点。很自然地想到扩展状态的维数,增加一维,记录倒数第二个点。
1> 设计状态:
dp[i , j , s]表示当前站在j点,前一个点是i点,形成的状态集合是s,此时的最大值,way[i , j , s]记录当前状态下达到最大值的路径数;
2> 状态转移:
设k点不在集合s中,且存在边<j , k>
设q为下步到达k点获得的最大值
令r = s + (1<<k),为当前站在点k,前一个点为j,形成状态集合r
若i,j,k形成三角形,则q = dp[i][j][s] + v[k] + v[j]*v[k] + v[i]*v[j]*v[k];
否则,q = dp[i][j][s] + v[k] + v[j]*v[k];
若q大于dp[j][k][r];则:
dp[j][k][r] = q
way[j][k][r] = way[i][j][s];
若q等于dp[j][k][r],则:
way[j][k][r] += way[i][j][s];
3> 初始化:
显然,若i点到j点有边,则:
dp[i][j][(1<<i)+(1<<j)] = v[i] + v[j] + v[i]*v[j];
way[i][j][(1<<i)+(1<<j)] = 1;
4> 结果的产生:
最后的结果我们要枚举点i和j,找到最大的dp[i][j][(1<<n)-1],并且更新记录路径数ansp,最后ansp要除2才是结果,因为题目最后一句话,正向反向是一样的路。
此外,需要注意的是discuss提到的特殊情况,要用__int64,并且注意n等于1时,最大值就是第一个点的权值,路径数为1。
(ps:在处理特殊情况时,忘记换行,还PE一次,这年头PE的还真少见啊。。。)
代码如下,祝1Y。
1 #include <stdio.h> 2 #include <string.h> 3 4 typedef __int64 i64; 5 6 const int maxn = 13; 7 const int maxs = 1<<maxn | 1; 8 9 i64 dp[maxn][maxn][maxs], way[maxn][maxn][maxs]; 10 int map[maxn][maxn], v[maxn]; 11 int n, m, S; 12 13 void StateCompressDp() { 14 15 memset(dp, -1, sizeof(dp)); 16 memset(way, 0, sizeof(way)); 17 for (int i = 0; i < n; i++) { 18 for (int j = 0; j < n; j++) { 19 if (map[i][j]) { 20 dp[i][j][(1<<i)+(1<<j)] = v[i] + v[j] + v[i]*v[j]; 21 way[i][j][(1<<i)+(1<<j)] = 1; 22 } 23 24 } 25 } 26 for (int p = 3; p < S; p++) { 27 for (int i = 0; i < n; i++) { 28 if (!(p&1<<i)) continue; 29 for (int j = 0; j < n; j++) { 30 if (i == j || !(p&1<<j) || dp[i][j][p] == -1) continue; 31 for (int k = 0; k < n; k++) { 32 if (p&1<<k || !map[j][k]) continue; 33 int r = p + (1 << k); 34 i64 q = dp[i][j][p] + v[k] + v[j]*v[k]; 35 if (map[i][k]) { 36 q += v[i] * v[j] * v[k]; 37 } 38 if (q > dp[j][k][r]) { 39 dp[j][k][r] = q; 40 way[j][k][r] = way[i][j][p]; 41 } else if (q == dp[j][k][r]) { 42 way[j][k][r] += way[i][j][p]; 43 } 44 } 45 } 46 } 47 } 48 49 return ; 50 } 51 52 int main () { 53 54 int t; 55 56 scanf("%d", &t); 57 while (t--) { 58 int tmpx, tmpy; 59 memset(map, 0, sizeof(map)); 60 scanf("%d%d", &n, &m); 61 for (int i = 0; i < n; i++) { 62 scanf("%d", &v[i]); 63 } 64 for (int i = 0; i < m; i++) { 65 scanf("%d%d", &tmpx, &tmpy); 66 map[tmpx-1][tmpy-1] = map[tmpy-1][tmpx-1] = 1; 67 } 68 S = 1 << n; 69 if (n == 1) { 70 printf("%d %d\n", v[0], 1); 71 } else { 72 StateCompressDp(); 73 i64 ansv = -1, ansp = 0; 74 for (int i = 0; i < n; i++) { 75 for (int j = 0; j < n; j++) { 76 if (i == j) continue; 77 if (dp[i][j][S-1] > ansv) { 78 ansv = dp[i][j][S-1]; 79 ansp = way[i][j][S-1]; 80 } else if (dp[i][j][S-1] == ansv) { 81 ansp += way[i][j][S-1]; 82 } 83 } 84 } 85 printf("%I64d %I64d\n", ansv == -1 ? 0 : ansv, ansp/2); 86 } 87 } 88 89 return 0; 90 }