两种求二分图匹配的姿势

UOJ #78. 二分图最大匹配

从前一个和谐的班级,有 nl 个是男生,有 nr 个是女生。编号分别为 1,,nl 和 1,,nr

有若干个这样的条件:第 v 个男生和第 u 个女生愿意结为配偶。

请问这个班级里最多产生多少对配偶?

输入格式

第一行三个正整数,nl,nr,m

接下来 m 行,每行两个整数 v,表示第 v 个男生和第 u 个女生愿意结为配偶。保证 1vnl1unr,保证同一个条件不会出现两次。

输出格式

第一行一个整数,表示最多产生多少对配偶。

接下来一行 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 号男生孤独终生。= =||

限制与约定

1nl,nr5001m250000

时间限制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;
}

  

posted @ 2017-10-18 16:53  Stump  阅读(200)  评论(0编辑  收藏  举报