#80. 二分图最大权匹配
统计
- 描述
- 提交
- 自定义测试
从前一个和谐的班级,有 $n_l$ 个是男生,有 $n_r$ 个是女生。编号分别为 $1, \dots, n_l$ 和 $1, \dots, n_r$。
有若干个这样的条件:第 $v$ 个男生和第 $u$ 个女生愿意结为配偶,且结为配偶后幸福程度为 $w$。
请问这个班级里幸福程度之和最大是多少?
输入格式
第一行三个正整数,$n_l, n_r, m$。
接下来 $m$ 行,每行三个整数 $v, u, w$ 表示第 $v$ 个男生和第 $u$ 个女生愿意结为配偶,且幸福程度为 $w$。保证 $1 \leq v \leq n_l$,$1 \leq u \leq n_r$,保证同一对 $v, u$ 不会出现两次。
输出格式
第一行一个整数,表示幸福程度之和的最大值。
接下来一行 $n_l$ 个整数,描述一组最优方案。第 $v$ 个整数表示 $v$ 号男生的配偶的编号。如果 $v$ 号男生没配偶请输出 $0$。
样例一
input
2 2 3 1 1 100 1 2 1 2 1 1
output
100 1 0
限制与约定
$1 \leq n_l, n_r \leq 400$,$1 \leq m \leq 160000$,$1 \leq w \leq 10^9$。
时间限制:$1\texttt{s}$
空间限制:$256\texttt{MB}$
递归版ed1
//用时 内存 语言 文件大小 //1787ms 1276kb C++ 1.7kb #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; using namespace std; typedef long long ll; const int N=505; const int inf=1e9+99; template<typename T> inline void read(T &x){ register bool f=0;register char ch=getchar();x=0; for(;ch<‘0‘||ch>‘9‘;ch=getchar()) if(ch==‘-‘) f=1; for(;ch>=‘0‘&&ch<=‘9‘;ch=getchar()) x=(x<<3)+(x<<1)+ch-‘0‘; if(f) x=-x; } template<typename T,typename...Args> void read(T &x,Args&...args){read(x);read(args...);} #define m(x) memset(x,0,sizeof x); bool visx[N],visy[N]; int nx,ny,n,m,slap[N],lx[N],ly[N],match[N],w[N][N]; bool hunguary(int x){ visx[x]=1; for(int y=1;y<=n;y++){ if(visy[y]) continue; int gap=lx[x]+ly[y]-w[x][y]; if(!gap){ visy[y]=1; if(!match[y]||hunguary(match[y])){ match[y]=x; return 1; } } else slap[y]=min(slap[y],gap); } return 0; } ll KM(){ for(int i=1;i<=n;i++) lx[i]=*max_element(w[i]+1,w[i]+n+1); for(int x=1;x<=n;x++){ fill(slap+1,slap+n+1,inf); m(visx);m(visy); if(hunguary(x)) continue; while(1){ int d=inf,t=0; for(int y=1;y<=n;y++) if(!visy[y]) d=min(d,slap[y]); for(int x=1;x<=n;x++) if(visx[x]) lx[x]-=d; for(int y=1;y<=n;y++) if(visy[y]) ly[y]+=d;else if(!(slap[y]-=d)) t=y; if(!match[t]) break; int v=match[t]; visx[v]=visy[t]=1; for(int y=1;y<=n;y++) slap[y]=min(slap[y],lx[v]+ly[y]-w[v][y]); } m(visx);m(visy); hunguary(x); } ll res=0; for(int i=1;i<=n;i++) res+=w[match[i]][i]; return res; } int main(){ read(nx,ny,m);n=max(nx,ny); for(int i=0,x,y,z;i<m;i++) read(x,y,z),w[y][x]=z; printf("%lld\n",KM()); for(int i=1;i<=nx;i++) printf("%d ",w[match[i]][i]?match[i]:0); return 0; }
循环版ed2
//用时 内存 语言 文件大小 //1758ms 1792kb C++ 1.1kb #include<stdio.h> #include<iostream> using namespace std; template<typename T> inline void read(T &x){ register bool f=0;register char ch=getchar();x=0; for(;ch<‘0‘||ch>‘9‘;ch=getchar()) if(ch==‘-‘) f=1; for(;ch>=‘0‘&&ch<=‘9‘;ch=getchar()) x=(x<<3)+(x<<1)+ch-‘0‘; if(f) x=-x; } template<typename T,typename...Args> void read(T &x,Args&...args){read(x);read(args...);} const int N=404,inf=1e9; bool vy[N];long long ans; int n,m,n1,n2,lx[N],ly[N],w[N][N],mt[N],sl[N],pre[N]; int main(){ read(n1,n2,m);n=max(n1,n2); for(int i=0,x,y,z;i<m;i++) read(x,y,z),w[y][x]=z,lx[y]=max(lx[y],z); for(int i=1,x,d,py,pn;i<=n;i++){ for(int j=1;j<=n;j++) sl[j]=inf,vy[j]=0; for(mt[py=0]=i;mt[py];py=pn){ vy[py]=1;d=inf;x=mt[py]; for(int y=1;y<=n;y++) if(!vy[y]){ if(lx[x]+ly[y]-w[x][y]<sl[y]) sl[y]=lx[x]+ly[y]-w[x][y],pre[y]=py; if(sl[y]<d) d=sl[y],pn=y; } for(int y=0;y<=n;y++) vy[y]?lx[mt[y]]-=d,ly[y]+=d:sl[y]-=d; } for(;py;py=pre[py]) mt[py]=mt[pre[py]]; } for(int i=1;i<=n;i++) ans+=lx[i]+ly[i]; printf("%lld\n",ans); for(int i=1;i<=n1;i++) printf("%d ",w[mt[i]][i]?mt[i]:0); return 0; }
原文地址:https://www.cnblogs.com/shenben/p/12255765.html
时间: 2024-12-11 04:46:59