poj 2404 Jogging Trails(欧拉图、状压DP)
http://poj.org/problem?id=2404
题意:
一张带权无向图,求选择一个起点,每条边至少被经过一遍,再回到起点的最小代价
加最小代价的边,使图变成欧拉图
无向图欧拉图:所有点的度数为偶数
抽离所有度数为奇数的点,状压dp
dp[i] 表示 状态为i的奇度数的点,度数变成偶数的最小代价
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define N 16 using namespace std; int d[N]; int dy[N]; int f[N][N]; int dp[1<<N-1]; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } int main() { int n,m; int u,v,w; int sum; while(1) { read(n); if(!n) return 0; read(m); memset(f,63,sizeof(f)); memset(d,0,sizeof(d)); for(int i=1;i<=n;++i) f[i][i]=0; sum=0; while(m--) { read(u); read(v); read(w); d[u]++; d[v]++; sum+=w; f[u][v]=f[v][u]=min(f[u][v],w); } for(int k=1;k<=n;++k) for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) f[i][j]=min(f[i][j],f[i][k]+f[k][j]); int cnt=0; for(int i=1;i<=n;++i) if(d[i]&1) dy[++cnt]=i; memset(dp,63,sizeof(dp)); dp[0]=0; int S=1<<cnt; for(int i=0;i<S;++i) { int x=1; while((1<<x-1)&i) x++; for(int y=x+1;y<=cnt;++y) if(!(i&1<<y-1)) dp[i|(1<<x-1)|(1<<y-1)]=min(dp[i|(1<<x-1)|(1<<y-1)],dp[i]+f[dy[x]][dy[y]]); } printf("%d\n",dp[S-1]+sum); } }