Description
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.
For each case, there should be one line of output giving the length of Gord's jogging route.
4 5 1 2 3 2 3 4 3 4 5 1 4 10 1 3 12 0
41中国邮路问题(Chinese Postman Problem)是一个非常经典的图论问题:一个邮递员送信,要走完他负责投递的全部街道(所有街道都是双向通行的且每条街道可以经过不止一次),
完成任务后回到邮局,应按怎样的路线走,他所走的路程才会最短呢?如果将这个问题抽象成图论的语言,就是给定一个连通图,每条边的权值就是街道的长度,本问题转化为在图中求
一条回路,使得回路的总权值最小。
如果街道的连通图为欧拉图,则只要求出图中的一条欧拉回路即可。否则,邮递员要完成任务就必须在某些街道上重复走若干次。如果重复走一次,就加一条平行边,于是原来对应的图形
就变成了多重图。只是要求加进的平行边的总权值最小就行了。于是,我们的问题就转化为,在一个有奇度数结点的赋权连通图中,增加一些平行边,使得新图不含奇度数结点,并且
增加的边的总权值最小。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 18; const int inf = 100; int dis[maxn][maxn], odd[maxn]; int dp[1<<maxn], deg[maxn]; int N, M, p; int cal(int status) { if (status == 0) return 0; if (dp[status] != -1) return dp[status]; int ans = 0x3f3f3f3f; for (int i = 0; i < p; i++) { if (status & (1<<i)) { for (int j = i+1; j < p; j++) if (status & (1<<j)) { int tmp = cal(status-(1<<i)-(1<<j)); ans = min(ans, tmp+dis[odd[i]][odd[j]]); } // break; //notice,加与不加效率有差 } } return dp[status] = ans; } int main() { while(scanf("%d%d", &N, &M) != EOF && N) { memset(dis, 63, sizeof(dis)); memset(dp, -1, sizeof(dp)); memset(deg, 0, sizeof(deg)); int sum = 0; while (M--) { int x, y, w; scanf("%d%d%d", &x, &y, &w); dis[x][y] = min(dis[x][y], w); dis[y][x] = min(dis[y][x], w); deg[x]++, deg[y]++; sum += w; } for (int k = 1; k <= N; k++) for (int i = 1; i <= N; i++) for (int j = 1; j <= N; j++) dis[i][j] = min(dis[i][j], dis[i][k]+dis[k][j]); int cnt = 0; for(int i = 1; i <= N; i++) if(deg[i] % 2) odd[cnt++]=i; p = cnt; printf("%d\n", sum + cal((1<<cnt)-1)); } return 0; }