为什么可以这样拆点在 这道题 都已经证明过
代码:
1 //题目上面说了“The only exception is that the first and the last city should be the same and this city is visited twice.” 2 //我还以为是起点要使用两次,没想到题意就是全部点连接之后出入度都为1 3 4 //题意:有n座城市,m条带权有向边。有人想要游历所有城市,于是制定了计划:游历的路径是一个或者多个环,且所有城市都必须仅存在于一个环中。问怎样设计路线使得总路程最短? 5 //我们可以用最大权匹配去求: 6 //1.对于每个点u,我们拆成u和u'。u代表着出点,在二分图的左侧;u'代表着入点,在二分图的右侧。 7 //2.如果有一条有向边u-->v,那么在二分图中,我们加一条边u-->v',并且权值取反。 8 // 9 //3.利用KM()算法,求出最大权匹配,再将结果取反,即为答案。 10 // 举个三个点的例子 11 // p->q`->q->r`->r->p` 12 // 13 //问:为何KM()算法求出来的就一定是一个或多个环呢? 14 //1.可知,题目已经说明了必定有解。那么对应的二分图必定存在完全匹配,完全匹配也必定是最大匹配。 15 //2.我们用KM()算法求出了最大权匹配。根据性质:最大权匹配必定为最大匹配。所以,如果最大匹配是完全匹配,那么最大权匹配也是完全匹配。 16 //3.因为最大权匹配是完全匹配。所以所求出的解必定是一个或多个环。 17 #include<stdio.h> 18 #include<algorithm> 19 #include<string.h> 20 #include<iostream> 21 #include<queue> 22 #include<vector> 23 using namespace std; 24 const int maxn=510; 25 const int INF=0x3f3f3f3f; 26 int n,m; 27 int g[maxn][maxn],link[maxn],matchx[maxn],matchy[maxn]; 28 int slack[maxn],visitx[maxn],visity[maxn]; 29 int dfs(int x) 30 { 31 visitx[x]=1; 32 for(int i=1;i<=n;++i) 33 { 34 if(visity[i]) continue; 35 int temp=matchx[x]+matchy[i]-g[x][i]; 36 if(temp==0) 37 { 38 visity[i]=1; 39 if(link[i]==-1 || dfs(link[i])) 40 { 41 link[i]=x; 42 return 1; 43 } 44 } 45 else slack[i]=min(slack[i],temp); 46 } 47 return 0; 48 } 49 int km() 50 { 51 memset(link,-1,sizeof(link)); 52 memset(matchy,0,sizeof(matchy)); 53 for(int i=1;i<=n;++i) 54 { 55 matchx[i]=-INF; 56 for(int j=1;j<=n;++j) 57 { 58 matchx[i]=max(matchx[i],g[i][j]); 59 } 60 } 61 for(int x=1;x<=n;++x) 62 { 63 for(int i=1;i<=n;++i) 64 slack[i]=INF; 65 while(1) 66 { 67 memset(visitx,0,sizeof(visitx)); 68 memset(visity,0,sizeof(visity)); 69 if(dfs(x)) break; 70 int d=INF; 71 for(int i=1;i<=n;++i) 72 if(!visity[i]) 73 d=min(d,slack[i]); 74 for(int i=1;i<=n;++i) 75 { 76 if(visitx[i]) 77 matchx[i]-=d; 78 } 79 for(int i=1;i<=n;++i) 80 { 81 if(visity[i]) matchy[i]+=d; 82 else slack[i]-=d; 83 } 84 } 85 } 86 int ans=0; 87 for(int i=1;i<=n;++i) 88 { 89 if(link[i]!=-1) 90 ans+=g[link[i]][i]; 91 } 92 return ans; 93 } 94 int main() 95 { 96 int t; 97 scanf("%d",&t); 98 while(t--) 99 { 100 scanf("%d%d",&n,&m); 101 memset(g,0,sizeof(g)); 102 for(int i=1;i<=n;++i) 103 { 104 for(int j=1;j<=n;++j) 105 { 106 g[i][j]=-INF; 107 } 108 } 109 while(m--) 110 { 111 int u,v,w; 112 scanf("%d%d%d",&u,&v,&w); 113 g[u][v]=max(-w,g[u][v]); 114 } 115 printf("%d\n",-km()); 116 } 117 return 0; 118 }