题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1086
题意:给出n个顶点m条边的无向图。从其中某个顶点出发将每条边遍历至少一次回到出发点。求最短路。
思路:欧拉回路的每个点的度必为偶数。所以只要将所有度数为奇数的点找出,将其两两之间的最短路求出,状态压缩记忆化搜索即可。度数为奇数的点必为偶数个。因为每条边连两个顶点,所以所有点的总度数为偶数,假设奇度的点有x个,则偶度得点n-x个,可以x必为偶数。所以只要在奇度点之间每两个连一条边即可。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #define min(x,y) ((x)<(y)?(x):(y)) 5 using namespace std; 6 7 const int INF=1000000000; 8 int C,num=0; 9 int a[20][20],sum,f[(1<<16)+5],deg[20],b[20][20]; 10 int n,m; 11 12 void init() 13 { 14 int i,j,k; 15 for(k=1;k<=n;k++) for(i=1;i<=n;i++) for(j=1;j<=n;j++) 16 a[i][j]=min(a[i][j],a[i][k]+a[k][j]); 17 int temp[20],num=0,u,v; 18 for(i=1;i<=n;i++) if(deg[i]&1) temp[++num]=i; 19 for(i=1;i<=num;i++) for(j=1;j<=num;j++) 20 { 21 u=temp[i]; 22 v=temp[j]; 23 b[i-1][j-1]=a[u][v]; 24 } 25 n=num; 26 } 27 28 int DFS(int st) 29 { 30 if(st==(1<<n)-1) return 0; 31 if(f[st]!=-1) return f[st]; 32 f[st]=INF; 33 int i,j,st0; 34 for(i=0;i<n;i++) if(!(st&(1<<i))) for(j=i+1;j<n;j++) if(!(st&(1<<j))) 35 { 36 st0=st|(1<<i)|(1<<j); 37 f[st]=min(f[st],b[i][j]+DFS(st0)); 38 } 39 return f[st]; 40 } 41 42 int main() 43 { 44 for(scanf("%d",&C);C--;) 45 { 46 scanf("%d%d",&n,&m); 47 sum=0; 48 int i,j,u,v,w; 49 for(i=1;i<=n;i++) 50 { 51 for(j=1;j<=n;j++) a[i][j]=INF; 52 a[i][i]=0; 53 } 54 memset(deg,0,sizeof(deg)); 55 for(i=1;i<=m;i++) 56 { 57 scanf("%d%d%d",&u,&v,&w); 58 a[u][v]=a[v][u]=min(a[u][v],w); 59 deg[u]++; 60 deg[v]++; 61 sum+=w; 62 } 63 init(); 64 memset(f,-1,sizeof(f)); 65 printf("Case %d: %d\n",++num,sum+DFS(0)); 66 } 67 return 0; 68 }