P3386 Dinic求解二分图最大匹配

【模板】二分图最大匹配

题目描述

给定一个二分图,其左部点的个数为 \(n\),右部点的个数为 \(m\),边数为 \(e\),求其最大匹配的边数。

左部点从 \(1\)\(n\) 编号,右部点从 \(1\)\(m\) 编号。

输入格式

输入的第一行是三个整数,分别代表 \(n\)\(m\)\(e\)

接下来 \(e\) 行,每行两个整数 \(u, v\),表示存在一条连接左部点 \(u\) 和右部点 \(v\) 的边。

输出格式

输出一行一个整数,代表二分图最大匹配的边数。

样例 #1

样例输入 #1

1 1 1
1 1

样例输出 #1

1

样例 #2

样例输入 #2

4 2 7
3 1
1 2
3 2
1 1
4 2
4 1
1 1

样例输出 #2

2

提示

数据规模与约定

对于全部的测试点,保证:

  • \(1 \leq n, m \leq 500\)
  • \(1 \leq e \leq 5 \times 10^4\)
  • \(1 \leq u \leq n\)\(1 \leq v \leq m\)

不保证给出的图没有重边

关键在于如何建模

我们 取 s=1 t=n+m+2

对 s和1~n连边 1(n+2)~m(n+m+1)和 t连边

由于我们要看最后能有几条路径能从s->t 所以每条正向边我们流量设为1

这样只要 s->ni->mi->t 那么对于maxflow的贡献就+1 即为匹配个数

这样建模后我们跑 s->t的最大流即可

Dicnic可以在O(n√e)内求解

注意开始建边的时候只有正向赋1 反向边是0(🤣)

#include<bits/stdc++.h>//Dicnic最大流解决二分图最大匹配问题 
using namespace std;
#define int long long
const int inf=LONG_LONG_MAX;
const int N=1e5+5;
int n,m,e;
struct Graph {
	int from,nxt,to,val;
} edge[N<<1];
int head[N],cnt=1;
inline void add(int u,int v,int w) {
	cnt++;
	edge[cnt].to=v;
	edge[cnt].from=u;
	edge[cnt].nxt=head[u];
	edge[cnt].val=w;
	head[u]=cnt;
}
int cur[N],dep[N],inque[N];
int s,t;
int g[505][505];
bool bfs() {
	queue<int>q;
	for(int i=1; i<=n+m+2; i++) {
		inque[i]=0;
		dep[i]=inf;
		cur[i]=head[i];
	}
	dep[s]=0;
	q.push(s);
	inque[s]=1;
	while(!q.empty()) {
		int u=q.front();
		q.pop();
		inque[u]=0;
		for(int i=head[u]; i; i=edge[i].nxt) {
			int v=edge[i].to;
			if(dep[v]>dep[u]+1&&edge[i].val) {
				dep[v]=dep[u]+1;
				if(!inque[v]) {
					inque[v]=1;
					q.push(v);
				}
			}
		}
	}
	if(dep[t]!=inf)return 1;
	return 0;
}
int dfs(int u,int flow) {
	if(u==t)return flow;
	int rlow;
	for(int i=cur[u]; i; i=edge[i].nxt) {
		cur[u]=i;
		int v=edge[i].to;
		if(edge[i].val&&dep[v]==dep[u]+1) {
			if(rlow=dfs(v,min(flow,edge[i].val))) {
				edge[i].val-=rlow;
				edge[i^1].val+=rlow;
				return rlow;
			}
		}
	}
	return 0;
}
int maxflow=0;
int Dicnic() {
	int flow;
	while(bfs()) {
		while(flow=dfs(s,inf))
			maxflow+=flow;
	}
	return maxflow;
}
signed main() {
	ios::sync_with_stdio(false);
	cin>>n>>m>>e;
	s=1,t=n+m+2;
	for(int i=1; i<=n; i++) {
		add(1,i+1,1);
		add(i+1,1,0);
	}
	for(int i=1; i<=e; i++) {
		int u,v;
		cin>>u>>v;
		add(u+1,v+n+1,1);
		add(v+n+1,u+1,0);
		g[u][v]=g[v][u]=1;
	}
	for(int i=1; i<=m; i++) {
		add(i+n+1,n+m+2,1);
		add(n+m+2,i+n+1,0);
	}
	cout<<Dicnic()<<"\n";
	return 0;
}

Dicnic多打几遍就对其有很充分的了解了

posted @ 2023-04-20 19:52  N0zoM1z0  阅读(9)  评论(0编辑  收藏  举报