HDU 3435 A new Graph Game(二分图最优匹配:有向环覆盖)
http://acm.hdu.edu.cn/showproblem.php?pid=3435
题意:
给你一个N个节点M条边的无向图,要你求该图有1个或多个不相交有向环(哈密顿回路)构成时,所有这些有向环的最小权值.
分析:
要注意,可以从本题的第3个用例的输出可以看出,本题的无向边,其实就是等效于两条方向相反的有向边.(如果本题的无向边==一条有向边,那么用例3无解). 所以对于本题来说无向图其实就是有向图的所有边必须添加两边(仅此而已),本题与之前所做的该类型题目几乎一样的解法.就不在赘述了.
注意:本题有重边.
具体分析可以参考HDU1853:
http://blog.csdn.net/u013480600/article/details/38760767
AC代码:
#include<cstdio> #include<cstring> #include<algorithm> #define INF 1e9 using namespace std; const int maxn=1000+10; struct Max_Match { int n,W[maxn][maxn]; int Lx[maxn],Ly[maxn]; bool S[maxn],T[maxn]; int left[maxn]; bool match(int i) { S[i]=true; for(int j=1;j<=n;j++)if(Lx[i]+Ly[j]==W[i][j] && !T[j]) { T[j]=true; if(left[j]==-1 || match(left[j])) { left[j]=i; return true; } } return false; } void update() { int a=1<<30; for(int i=1;i<=n;i++)if(S[i]) for(int j=1;j<=n;j++)if(!T[j]) a=min(a,Lx[i]+Ly[j]-W[i][j]); for(int i=1;i<=n;i++) { if(S[i]) Lx[i]-=a; if(T[i]) Ly[i]+=a; } } int solve(int n) { this->n=n; memset(left,-1,sizeof(left)); for(int i=1;i<=n;i++) { Lx[i]=Ly[i]=0; for(int j=1;j<=n;j++) Lx[i]=max(Lx[i],W[i][j]); } for(int i=1;i<=n;i++) { while(true) { for(int j=1;j<=n;j++) S[j]=T[j]=false; if(match(i)) break; else update(); } } int ans=0; for(int i=1;i<=n;i++) if(W[left[i]][i]==-INF) return -1; else ans+= W[left[i]][i]; return -ans; } }KM; int main() { int T; scanf("%d",&T); for(int kase=1;kase<=T;kase++) { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) KM.W[i][j]=-INF; for(int i=1;i<=m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); KM.W[u][v]=KM.W[v][u]=max(KM.W[u][v],-w); } int ans=KM.solve(n); if(ans==-1) printf("Case %d: NO\n",kase); else printf("Case %d: %d\n",kase,ans); } return 0; }