题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1853
我的链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=17728#problem/C
KM算法模板:http://blog.csdn.net/cfreezhan/article/details/8246639
用KM求最小费用模板题:http://blog.csdn.net/cfreezhan/article/details/8256926
6 9 1 2 5 2 3 5 3 1 10 3 4 12 4 1 8 4 6 11 5 4 7 5 6 9 6 5 4 6 5 1 2 1 2 3 1 3 4 1 4 5 1 5 6 1
42 -1HintIn the first sample, there are two cycles, (1->2->3->1) and (6->5->4->6) whose length is 20 + 22 = 42.
题意:找出若干个环,覆盖所有的点,使得总花费最小。
思路:以城市的个数建图,初始化为最小值(大负数),注意重复路径,以长度的负值求KM,
从而求出最大匹配,返回负值即是最短路径。
//Accepted 300 KB 46 ms C++ 1463 B 2013-02-26 15:42:24
//Accepted 300 KB 46 ms C++ 1463 B 2013-02-26 15:42:24 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=110; const int minn=-1<<30; char map[maxn][maxn]; int w[maxn][maxn]; int lx[maxn],ly[maxn];//顶标 bool s[maxn],t[maxn];//s[i]、t[i]为左/右第i个点是否已标记 int match[maxn]; int n; int hungary(int u)//匈牙利,匹配(找增广路) { s[u]=true;//标记入匈牙利树 for(int v=1;v<=n;v++) { if(!t[v] && lx[u]+ly[v]==w[u][v]) { t[v]=true;//标记入匈牙利树 易忘记 if(match[v]==-1 || hungary(match[v])) { match[v]=u; return true; } } } return false; } int KM() { int sum=0; memset(match,-1,sizeof(match));//初始化,易写错 for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) lx[i]=-1<<30;//初始化 顶标 memset(ly,0,sizeof(ly)); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) lx[i]=max(lx[i],w[i][j]);//最大权 for(int i=1;i<=n;i++)//匹配每一个点 { while(true) { memset(s,false,sizeof(s));//每次匹配前,找增广路,初始化为0 memset(t,false,sizeof(t)); if(hungary(i)) break; else{ int a=1<<30; for(int j=1;j<=n;j++) if(s[j])//j匹配过(即在匈牙利树中) for(int k=1;k<=n;k++) if(!t[k] && a>lx[j]+ly[k]-w[j][k]) a=lx[j]+ly[k]-w[j][k]; for(int j=1;j<=n;j++)//修改顶标 { if(s[j]) lx[j]-=a; if(t[j]) ly[j]+=a; } } } } for(int i=1;i<=n;i++) sum+=w[match[i]][i]; for(int i=1;i<=n;i++) if(w[match[i]][i]==minn) return 1;//匹配不成功 return sum; } int main() { int N,M; int u,v,length; while(scanf("%d%d",&N,&M)!=EOF) { n=N; for(int i=1;i<=N;i++) for(int j=1;j<=N;j++) w[i][j]=minn; for(int i=1;i<=M;i++) { scanf("%d%d%d",&u,&v,&length); if(-length>w[u][v]) w[u][v]=-length; } printf("%d\n",-KM()); } return 0; }