中国邮递员问题CPP


问题描述:Chinese poster-man  problem,简称CPP,给出一张连通图,问经过每条边至少一次且起点和终点相同,所需走的最小路程。

无向图CPP

1.考虑当所有点度数均为偶数时,该图是欧拉图,因此任意一条欧拉回路都是答案

2.当有两个点是奇度点的时候,只需找到这两点间的最短路径,将最短路径上的边计入到原图中,这是得到了一张欧拉图(poj 1237 The Postal Worker Rings Once

3.当奇度点个数大于2时,需要使每个点的度数均变为偶数,即在2n个点之间连n条路,于是变为了无向图的最小匹配问题(KM算法时错误的,因为无法保证解的正确性,带花树开花算法是正确的),一般采用状压dp解决该问题。(poj 2404 Jogging Trails)

对于每个奇度点,用一个二进制位表示,1代表尚未匹配,0代表已经匹配,寻找当前状态下尚未匹配的两点匹配同时更新状态,然后利用记忆化搜索寻找最优解。

import java.io.IOException;
import java.util.Arrays;
import java.util.Scanner;

public class Main {
	int dgr[] = new int[20];
	int map[][] = new int[20][20], inf = 1 << 28;
	Scanner scan = new Scanner(System.in);
	void floyd(int n) {
		for (int k = 1; k <=n; k++)
			for (int i = 1; i <=n; i++)
				for (int j = 1; j <=n; j++)
					map[i][j] = Math.min(map[i][j], map[i][k] + map[k][j]);
	}
	int stack[]=new int[20],top;
	int dp[]=new int[1<<17];
	int dfs(int s){
		if(s==0)
			return 0;
		if(dp[s]!=-1)
			return dp[s];
		int res=inf,i=0;
		while((s&(1< 0) {
				int a = scan.nextInt();
				int b = scan.nextInt();
				int c = scan.nextInt();
				map[b][a]=map[a][b] = Math.min(map[a][b], c);
				sum += c;
				dgr[a]++;
				dgr[b]++;
			}
			floyd(n);
			top=0;
			for(int i=1;i<=n;i++)
				if(dgr[i]%2==1)
					stack[top++]=i;
			Arrays.fill(dp, -1);
			sum+=dfs((1<

有向图CPP:

与无向图相同,都是试图用最小花费构造欧拉路,首先计算每个点的出度和入度的差d(v),然后利用最小费用流求解即可,构图如下:

1 其顶点集为图G 的所有顶点,以及附加的超级源s和超级汇t ;
2 对于图G 中每一条边(u ,v ),在N 中连边(u ,v ),容量为inf,费用为该边的长度;
3 从源点s 向所有d (v) <0的顶点v 连边(s,v),容量为-d (v),费用为0;
4 从所有d (v) > 0的顶点u 向汇点t 连边(u ,t),容量为d (v ),费用为0。

混合图CPP:

如果部分街道能够双向通行,部分街道只能单向通行。这个问题已被证明是NPC的。


你可能感兴趣的:(ACM•图论)