POJ 2404 Jogging Trails (中国邮递员问题,状态压缩DP)

题意:Gord在为一场马拉松做准备,他家后面有一个公园,公园里有许多路径,这些路径连接了水上景点(n<=15)。Gord训练的时候想走遍所有的路径至少一次,问她所需要走的最短路程是多长。

题解:计算出任意两点之间的路径,统计出奇度顶点,找出这些奇度顶点的最小带权匹配(貌似计算一般图的最优带权匹配不太好弄,拆点然后用KM做是不对的)。有一个算法叫做Edmonds-Johnson算法可以解决中国邮递员问题,但是我找不到具体代码。


#include 
using namespace std;

#define MAXN 30
#define INF 999999999
#define min(a,b) ( (a)<(b) ? (a):(b) )

int deg[MAXN];
int edge[MAXN][MAXN];
int dp[1<<15];

void Floyd ( int n )
{
	for ( int k = 1; k <= n; k++ )
		for ( int i = 1; i <= n; i++ )
			if ( edge[i][k] != INF )
			    for ( int j = 1; j <= n; j++ )
					if ( edge[k][j] != INF )
					    edge[i][j] = min ( edge[i][j], edge[i][k] + edge[k][j] );
}

int dfs ( int st, int n )
{
	if ( st == 0 ) return 0;
	if ( dp[st] > 0 ) return dp[st];

	dp[st] = INF;
	for ( int i = 1; i <= n; i++ )
	{
		if ( st & (1<<(i-1)) )
		{
			for ( int j = 1; j <= n; j++ )
				if ( i != j && (st & (1<<(j-1))) )
				{
					int tmp = dfs ( st^(1<<(i-1))^(1<<(j-1)), n ) + edge[i][j];
					if ( dp[st] > tmp ) dp[st] = tmp;
				}
		}
	}
	return dp[st];
}

int main()
{
	int n, m, u, v, l, i, j;
	int res, st;
	while ( scanf("%d",&n) && n )
	{
		scanf("%d",&m);;
		for ( i = 1; i <= n; i++ )
			for ( j = 1; j <= n; j++ )
				edge[i][j] = INF;

		res = 0;
		memset(deg,0,sizeof(deg));
		
		while ( m-- )
		{
			scanf("%d%d%d",&u,&v,&l);
			if ( edge[u][v] > l )
				edge[u][v] = edge[v][u] = l;
			res += l; deg[u]++; deg[v]++;
		}

		Floyd ( n );
		for ( st = 0, i = 1; i <= n; i++ )
			if ( deg[i] % 2 == 1 )
				st |= (1<<(i-1));

		memset(dp,-1,sizeof(dp));
		res = res + dfs ( st, n );
		printf("%d\n",res);
	}
	return 0;
}

你可能感兴趣的:(动态规划,图论/网络流)