POJ-2404 Jogging Trails (中国邮递员)

来源:互联网 发布:淘宝网男士真皮皮衣 编辑:程序博客网 时间:2024/05/22 01:34
Jogging Trails
Time Limit: 1000MS Memory Limit: 65536K   

Description

Gord is training for a marathon. Behind his house is a park with a large network of jogging trails connecting water stations. Gord wants to find the shortest jogging route that travels along every trail at least once.

Input

Input consists of several test cases. The first line of input for each case contains two positive integers: n <= 15, the number of water stations, and m < 1000, the number of trails. For each trail, there is one subsequent line of input containing three positive integers: the first two, between 1 and n, indicating the water stations at the end points of the trail; the third indicates the length of the trail, in cubits. There may be more than one trail between any two stations; each different trail is given only once in the input; each trail can be travelled in either direction. It is possible to reach any trail from any other trail by visiting a sequence of water stations connected by trails. Gord's route may start at any water station, and must end at the same station. A single line containing 0 follows the last test case.

Output

For each case, there should be one line of output giving the length of Gord's jogging route.

Sample Input

4 51 2 32 3 43 4 51 4 101 3 120

Sample Output

41
————————————————————失落的分割线————————————————————
前言:网络赛还是有我没我一个样。。。你懂得。我的DP是在是战五渣。打算把HDU上的DP专题做完!
思路:这是中国邮递员问题。因为点的个数很少,所以可以采用状态压缩+DP水掉。是有高端解法的。查了很久的资料,说是Edmonds的算法,带花树,KM最小权匹配什么的。
如果简单地想,就是想要“制造”最小的欧拉回路。存在奇度点(可以证明,一个图当中,奇度点的个数一定是偶数的:一条边产生两个点),想要通过添加最小的重边的方法来制造一个欧拉回路出来。
那么将这些奇度点进行配对。在配对的时候自然会遇到可能无法直接连接两个奇度点的情况。这个时候,而且直接连也不一定是最小的权。
因此跑一次Floyd预处理。这样一来奇数点就可以直接配对。通过状态压缩将奇度点压成一个int,然后取出第一个奇度点,枚举后面的奇度点,进行DP(记忆化搜索)。
代码如下:
/*ID: j.sure.1PROG:LANG: C++*//****************************************/#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <cmath>#include <stack>#include <queue>#include <vector>#include <map>#include <string>#include <climits>#include <iostream>#define INF 0x3f3f3f3fusing namespace std;/****************************************/const int N = 16;int G[N][N], deg[N];int st, dp[1<<15], n, m;int dfs(int st){if(st == 0) return 0;if(~dp[st]) return dp[st];int i;for(i = 1; i <= n; i++) if(st&(1<<i-1)) break;//第一个奇度点int mini = INF;//以下是DP过程for(int j = i+1; j <= n; j++) if(st&(1<<j-1)) {int t = dfs(st^(1<<i-1)^(1<<j-1)) + G[i][j];mini = min(mini, t);}return dp[st] = mini;}void Floyd(){for(int k = 1; k <= n; k++) {for(int i = 1; i <= n; i++) {for(int j = 1; j <= n; j++) if(k != i && k != j) {G[i][j] = min(G[i][j], G[i][k] + G[k][j]);}}}}int main(){#ifdef J_Sure//freopen("000.in", "r", stdin);//freopen(".out", "w", stdout);#endifwhile(scanf("%d", &n), n) {scanf("%d", &m);memset(G, 0x3f, sizeof(G));memset(deg, 0, sizeof(deg));int ans = 0, u, v, w;for(int i = 1; i <= m; i++) {scanf("%d%d%d", &u, &v, &w);G[u][v] = G[v][u] = min(G[u][v], w);ans += w;deg[u]++; deg[v]++;}st = 0;for(int i = 1; i <= n; i++) {if(deg[i]&1) {st |= 1<<(i-1);//状态压缩}}if(st == 0) {printf("%d\n", ans);//本身就存在欧拉回路}else {Floyd();memset(dp, -1, sizeof(dp));ans += dfs(st);printf("%d\n", ans);}}return 0;}


0 0