题意:Gord在为一场马拉松做准备,他家后面有一个公园,公园里有许多路径,这些路径连接了水上景点(n<=15)。Gord训练的时候想走遍所有的路径至少一次,问她所需要走的最短路程是多长。
题解:计算出任意两点之间的路径,统计出奇度顶点,找出这些奇度顶点的最小带权匹配(貌似计算一般图的最优带权匹配不太好弄,拆点然后用KM做是不对的)。有一个算法叫做Edmonds-Johnson算法可以解决中国邮递员问题,但是我找不到具体代码。
#include <iostream> 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; }