题意:给定一张图,要求从起点出发走遍每一条边并回到起点的最短路径。。
思路:由一笔画问题可知,想满足题意每个点必须是偶点(度为偶数),所以首先用floyed做一遍最短路,
找到奇点之间的最短路径。。
接下来便是用状态压缩dp就可决解。。
1 /* 2 State:Accepted 3 Time:2013-03-21 14:50:26 4 */ 5 #include<cstdio> 6 #include<cstdlib> 7 #include<fstream> 8 #include<queue> 9 #include<stack> 10 #include<algorithm> 11 #include<vector> 12 #include<list> 13 #include<set> 14 #include<string> 15 #include<cstring> 16 #include<map> 17 #include<cmath> 18 #include<iostream> 19 #define M0(NAME) memset(NAME, 0 , sizeof(NAME)) 20 using namespace std; 21 const int maxn = 1 << 15; 22 int f[maxn + 10], a[21][21] , n , m ,ans , du[21] ,opt; 23 24 void init(){ 25 int x , y ,z; 26 M0(du); 27 M0(f); 28 ans = 0; 29 scanf("%d",&m); 30 for (int i = 1; i <= 20; ++i) 31 for (int j = 1; j <= 20; ++j) 32 a[i][j] = 0xfffffff; 33 for (int i = 0; i < m; ++i){ 34 scanf("%d%d%d", &x, &y ,&z); 35 if (z < a[x][y]) 36 a[x][y] = a[y][x] = z; 37 38 ans += z; 39 ++du[x]; 40 ++du[y]; 41 42 } 43 } 44 45 void floyed(){ 46 for (int k = 1; k <= n; ++k) 47 for (int i = 1; i <= n; ++i) 48 for (int j = 1; j <= n; ++j){ 49 if (i == j || j == k || i == k) continue; 50 a[i][j] = min(a[i][j] , a[i][k] + a[k][j]); 51 } 52 } 53 54 55 int dfs(int opt){ 56 if (opt == 0) return 0; 57 if (f[opt]>0) return f[opt]; 58 int tm = 0xfffffff, temp; 59 for (int i = 1; i < n; ++i) 60 if (1<< i-1 & opt) 61 for (int j = i + 1; j <= n; ++j) 62 if (1<< j-1 & opt){ 63 temp = dfs(opt - (1 << i - 1) - (1 << j - 1)) + a[i][j]; 64 tm = min(tm ,temp); 65 } 66 return f[opt] = tm; 67 68 } 69 int main(){ 70 freopen("poj2404.in","r",stdin); 71 freopen("poj2404.out","w",stdout); 72 while (~scanf("%d", &n) && n){ 73 init(); 74 floyed(); 75 opt = 0; 76 for (int i = 1; i <= n; ++i) 77 if (du[i] % 2 == 1) opt |= (1 << i - 1); 78 ans += dfs(opt); 79 printf("%d\n",ans); 80 } 81 82 return 0; 83 }