两种求二分图匹配的姿势
UOJ #78. 二分图最大匹配
从前一个和谐的班级,有 nl 个是男生,有 nr 个是女生。编号分别为 1,…,nl 和 1,…,nr。
有若干个这样的条件:第 v 个男生和第 u 个女生愿意结为配偶。
请问这个班级里最多产生多少对配偶?
输入格式
第一行三个正整数,nl,nr,m。
接下来 m 行,每行两个整数 v,u 表示第 v 个男生和第 u 个女生愿意结为配偶。保证 1≤v≤nl,1≤u≤nr,保证同一个条件不会出现两次。
输出格式
第一行一个整数,表示最多产生多少对配偶。
接下来一行 nl 个整数,描述一组最优方案。第 v 个整数表示 v 号男生的配偶的编号。如果 v 号男生没配偶请输出 0。
样例一
input
2 2 3 1 1 1 2 2 1
output
2 2 1
explanation
1 号男生跟 2 号女生幸福地生活在了一起~
2 号男生跟 1 号女生幸福地生活在了一起~
样例二
input
2 2 2 1 1 2 1
output
1 1 0
explanation
班上一个女神一个女汉子,两个男生都去追女神。一种最优方案是:
1 号男生跟 1 号女生幸福地生活在了一起~
2 号男生孤独终生。= =||
限制与约定
1≤nl,nr≤500,1≤m≤250000。
时间限制:1s
空间限制:256MB
下载
最大流dinic算法
#include<cstdio> #include<queue> #include<iostream> #define INF 2147483647 #define BIG 1000011 std::queue<int>q; int nxt[BIG],las[BIG],to[BIG],w[BIG],dep[BIG]; int nl,nr,m,tot=1; int x,y,S,T; inline void add(int x,int y,int z){ nxt[++tot]=las[x]; las[x]=tot; to[tot]=y; w[tot]=z; } inline int bfs(){ for(register int i=1;i<=T;++i) dep[i]=0; dep[S]=1; q.push(S); int now; while(!q.empty()){ now=q.front(); q.pop(); for(register int e=las[now];e;e=nxt[e]) if(w[e]&&!dep[to[e]]){ dep[to[e]]=dep[now]+1; q.push(to[e]); } } return dep[T]; } inline int dfs(int now,int f){ if(now==T) return f; int ret=0,d; for(register int e=las[now];e&&f;e=nxt[e]) if(w[e]&&dep[to[e]]==dep[now]+1){ d=dfs(to[e],std::min(w[e],f)); f-=d; ret+=d; w[e]-=d; w[e^1]+=d; } if(!ret) dep[now]=0; return ret; } inline int dinic(){ int ans=0; while(bfs()) ans+=dfs(S,INF); return ans; } int main(){ scanf("%d%d%d",&nl,&nr,&m); S=nl+nr+1; T=nl+nr+2; for(register int i=1;i<=nl;++i) add(S,i,1),add(i,S,0); for(register int i=nl+1;i<=nl+nr;++i) add(i,T,1),add(T,i,0); for(register int i=1;i<=m;++i){ scanf("%d%d",&x,&y); add(x,y+nl,1),add(y+nl,x,0); } printf("%d\n",dinic()); for(register int i=1;i<=nl;++i){ for(register int e=las[i];e;e=nxt[e]) if(!w[e]&&to[e]!=S){ printf("%d",to[e]-nl); putchar(' '); goto sign; } putchar(48); putchar(' '); sign:; } return 0; }
匈牙利算法
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #define FOR(i,s,t) for(register int i=s;i<=t;++i) #define BIG 1000011 using namespace std; int n,m,t,x,y,tot,ans,cnt; int nxt[BIG],las[BIG],to[BIG],vis[BIG],con[BIG],have[BIG]; inline void add(int x,int y){ nxt[++tot]=las[x]; las[x]=tot; to[tot]=y; } inline int match(int now){ for(register int e=las[now];e;e=nxt[e]) if(!vis[to[e]]){ vis[to[e]]=1; have[++cnt]=to[e]; if(!con[to[e]]||match(con[to[e]])){ con[to[e]]=now; return 1; } } return 0; } int main(){ scanf("%d%d%d",&n,&m,&t); while(t--){ scanf("%d%d",&x,&y); add(y+n,x); } FOR(j,n+1,n+m){ while(cnt) vis[have[cnt--]]=0; ans+=match(j); } printf("%d\n",ans); FOR(i,1,n) printf("%d ",con[i]?con[i]-n:con[i]); return 0; }