CH0103最短Hamilton路径 & poj2288 Islands and Brigdes【状压DP】

虐狗宝典学习笔记:

取出整数\(n\)在二进制表示下的第\(k\)位                                                    \((n >> k) & 1)\)

取出整数\(n\)在二进制表示下的第\(0 ~ k - 1\)位(后\(k\)位)                    \(n & ((1 << k) - 1)\)

把整数\(n\)在二进制表示下的第\(k\)位取反                                                \(n xor (1 << k)\)

对整数\(n\)在二进制表示下的第\(k\)为赋值\(1\)                                          \(n | (1 << k)\)

对整数\(n\)在二进制表示下的第\(k\)位赋值\(0\)                                          \(n & (~(1 << k))\)

 

CH0103---最短Hamilton路径

http://contest-hunter.org:83/contest/0x00%E3%80%8C%E5%9F%BA%E6%9C%AC%E7%AE%97%E6%B3%95%E3%80%8D%E4%BE%8B%E9%A2%98/0103%20%E6%9C%80%E7%9F%ADHamilton%E8%B7%AF%E5%BE%84

题意:

hamilton指的是每个节点经过一次且仅经过一次的路径。现在路径上有权值,问最短的路径长度。

思路:

状压dp。\(dp[i][j]\)表示在状态是\(i\)且最后一个经过的点时\(j\)时的最短路径长度。

\(dp[i][j] = min{dp[i xor (i << j)][k] + weight(k, j)}\)

 1 #include <bits/stdc++.h>
 2 #define inf 0x3f3f3f3f
 3 using namespace std;
 4 typedef long long LL;
 5 
 6 int n;
 7 int g[25][25];
 8 int dp[1 << 20][25];
 9 
10 int main()
11 {
12     scanf("%d", &n);
13     memset(dp, 0x3f, sizeof(dp));
14     for(int i = 0; i < n; i++){
15         for(int j = 0; j < n; j++){
16             scanf("%d", &g[i][j]);
17         }
18     }
19     dp[1][0] = 0;
20     for(int i = 1; i < 1 << n; i++){
21         for(int j = 0; j < n; j++){
22             if(i >> j & 1){
23                 for(int k = 0; k  < n; k++){
24                     if((i ^ 1 << j) >> k & 1){
25                         dp[i][j] = min(dp[i][j], dp[i ^ 1 << j][k] + g[k][j]);
26                     }
27                 }
28             }
29         }
30     }
31 
32     printf("%d\n", dp[(1 << n) - 1][n - 1]);
33     return 0;
34 }

 

 

poj2288---Islands and Bridges

http://poj.org/problem?id=2288

题意:

有n个岛,m座桥。每座岛有一个val,一条汉密尔顿路径的值是路径中所有点的val之和,加上所有路径上相邻的两个岛的val乘积之和,加上路径上相邻的三个岛的val乘积之和。求最大的值以及方案数。

思路:

和CH0103很相近,不同的是这道题要多存一个岛。\(dp[stat][i][j]\)表示当前状态是\(stat\),最后一个走的岛是\(j\),倒数第二个走的岛是\(i\), \(num\)数组表示对应的方案数。

当\( (stat, i, j) \)可达时,我们检查下一个要走的岛\(k\),如果此时\( (stat >> k) & 1 == 0 \) 且 \( g[j][k] == 1 \)说明\(k\)是满足条件的

设\(tmp\)是下一个走\(k\)时的总价值。那么,\(dp[stat | (1 << k)][j][k] = max(dp[stat | (1 << k)][j][k], tmp)\)

如果\(tmp == dp[stat | (1 << k)][j][k]\),那么,\(num[stat | (1 << k)][j][k] += num[stat][i][j]\)。否则\(num[stat | (1 << k)][j][k] = num[stat][i][j] \)

那么要如何求\(tmp\) 呢。

首先当\(j\)可以走到\(k\)时,肯定有 \(tmp = dp[stat][i][j] + val[k] + val[j] * val[k] \)

如果此时还有\(g[i][k] == 1\) 那么\(tmp += val[i] * val[j] * val[k]\)

最后我们对于\(stat = (1 << n) - 1\)枚举\(i\)和\(j\),找到最大的结果。

注意方案数会超出int。还需要注意\(n = 1\)时的特殊情况。

注意内存省着点,会MLE

  1 //#include <bits/stdc++.h>
  2 #include <iostream>
  3 #include <algorithm>
  4 #include <cmath>
  5 #include <cstring>
  6 #include <stdio.h>
  7 #include <vector>
  8 #include <map>
  9 #include <set>
 10 #define inf 0x3f3f3f3f
 11 using namespace std;
 12 typedef long long LL;
 13 
 14 int n, m, q;
 15 bool g[13][13];
 16 int dp[1 << 13][13][13];
 17 LL num[1 << 13][13][13];
 18 int val[13];
 19 int cnt;
 20 
 21 void hamilton()
 22 {
 23     memset(dp, -1, sizeof(dp));
 24     memset(num, 0, sizeof(num));
 25     for(int i = 0; i < n; i++){
 26         for(int j = 0; j < n; j++){
 27             if(g[i][j]){
 28                 dp[1 << i | 1 << j][i][j] = val[i] + val[j] + val[i] * val[j];
 29                 num[1 << i | 1 << j][i][j] = 1;
 30             }
 31         }
 32     }
 33 
 34     for(int stat = 1; stat < 1 << n; stat++){
 35         for(int i = 0; i < n; i++){
 36             if((stat >> i) & 1){
 37                 for(int j = 0; j < n; j++){
 38                     if((stat >> j) & 1){
 39                         if(g[i][j] && dp[stat][i][j] != -1){
 40                             for(int k = 0; k < n; k++){
 41                                 if(g[j][k] && k != i && ((stat >> k) & 1) == 0){
 42                                     int tmp = dp[stat][i][j] + val[k] + val[k] * val[j];
 43                                     if(g[i][k]){
 44                                         tmp += val[i] * val[j] * val[k];
 45                                     }
 46                                     if(tmp > dp[stat | (1 << k)][j][k]){
 47                                         dp[stat | (1 << k)][j][k] = tmp;
 48                                         num[stat | (1 << k)][j][k] = num[stat][i][j];
 49                                     }
 50                                     else if(tmp == dp[stat | (1 << k)][j][k]){
 51                                         num[stat | (1 << k)][j][k] += num[stat][i][j];
 52                                     }
 53                                 }
 54                             }
 55                         }
 56                     }
 57                 }
 58             }
 59         }
 60     }
 61     //return dp[(1 << n) - 1][n - 1];
 62 }
 63 
 64 int main()
 65 {
 66     scanf("%d", &q);
 67     while(q--){
 68         memset(g, 0, sizeof(g));
 69         scanf("%d%d", &n, &m);
 70         for(int i = 0; i < n; i++){
 71             scanf("%d", &val[i]);
 72         }
 73         for(int i = 0; i < m; i++){
 74             int u, v;
 75             scanf("%d%d", &u, &v);
 76             g[u - 1][v - 1] = 1;
 77             g[v - 1][u - 1] = 1;
 78         }
 79         if(n == 1){
 80             printf("%d 1\n", val[0]);
 81             continue;
 82         }
 83 
 84         hamilton();
 85         int maxi = 0;
 86         LL ans = 0;
 87         for(int i = 0; i < n; i++){
 88             for(int j = 0; j < n; j++){
 89                 if(g[i][j]){
 90                     if(maxi < dp[(1 << n) - 1][i][j]){
 91                         maxi = dp[(1 << n) - 1][i][j];
 92                         ans = num[(1 << n) - 1][i][j];
 93                     }
 94                     else if(maxi == dp[(1 << n) - 1][i][j]){
 95                         ans += num[(1 << n) - 1][i][j];
 96                     }
 97                 }
 98             }
 99         }
100 
101         printf("%d %lld\n", maxi, ans / 2);
102     }
103     return 0;
104 }

 

posted @ 2018-11-08 21:27  wyboooo  阅读(175)  评论(0编辑  收藏  举报