两种求二分图匹配的姿势
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;
}

浙公网安备 33010602011771号