bestcoder Round#52 1001(最短路+状压dp)
求从1点出发,走遍所有的点,然后回到1点的最小代价。
每个点可以走若干遍。
如果每个点只能走一遍,那么设dp[i][s]为走完s状态个点(s是状态压缩),现在位于i的最小花费。
然后枚举从哪个点回到原点即可。
但是现在每个点不止走一次,那么状态就不好表示了,但是,我们可以用floyd处理出任意两点的最短距离。
这样子,可以用上面的方式求解了。
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <algorithm> 5 #include <iostream> 6 #include <queue> 7 #include <stack> 8 #include <vector> 9 #include <map> 10 #include <set> 11 #include <string> 12 #include <math.h> 13 using namespace std; 14 #pragma warning(disable:4996) 15 #pragma comment(linker, "/STACK:1024000000,1024000000") 16 typedef __int64 LL; 17 const int INF = 100000000; 18 /* 19 20 21 22 */ 23 int dp[17][70000]; 24 int dist[20][20]; 25 int g[20][20]; 26 void input(int &x) 27 { 28 char ch = getchar(); 29 while (ch<'0' || ch>'9')ch = getchar(); 30 x = 0; 31 while (ch >= '0'&&ch <= '9') 32 { 33 x = x * 10 + ch - '0'; 34 ch = getchar(); 35 } 36 } 37 int ans; 38 39 int main() 40 { 41 //freopen("d:/1.in", "r", stdin); 42 int t, n, m, u, v,dis; 43 scanf("%d", &t); 44 while (t--) 45 { 46 scanf("%d%d", &n, &m); 47 for (int i = 0; i <= n; ++i) 48 for (int j = 0; j <= n; ++j) 49 { 50 g[i][j] = INF; 51 } 52 for (int i = 0; i < m; ++i) 53 { 54 input(u); 55 input(v); 56 input(dis); 57 u--; 58 v--; 59 if (g[u][v]>dis) 60 g[u][v] = g[v][u] = dis; 61 } 62 for (int k = 0; k < n; ++k) 63 { 64 for (int i = 0; i < n;++i) 65 for (int j = 0; j < n; ++j) 66 g[i][j] = min(g[i][j],g[i][k]+ g[k][j]); 67 } 68 69 70 for (int i = 0; i <= n; ++i) 71 for (int s = 0; s < (1 << n); ++s) 72 dp[i][s] = INF; 73 dp[0][1] = 0; 74 for (int s = 1; s < (1 << n); ++s) 75 { 76 for (int i = 0; i < n; ++i) 77 { 78 if (s&(1 << i)) 79 { 80 for (int j = 0; j < n; ++j) 81 { 82 if (!(s&(1 << j))) 83 { 84 dp[j][s | (1 << j)] = min(dp[j][s | (1 << j)], dp[i][s] + g[i][j]); 85 } 86 } 87 } 88 } 89 } 90 if (n == 1) 91 { 92 printf("%d\n", 0); 93 continue; 94 } 95 int ans = INF; 96 for (int i = 1; i < n; ++i) 97 { 98 ans = min(dp[i][(1 << n) - 1] + g[i][0], ans); 99 } 100 printf("%d\n", ans); 101 } 102 return 0; 103 }