P3386 二分图最大匹配 匈牙利算法

【模板】二分图最大匹配

题目描述

给定一个二分图,其左部点的个数为 \(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\)

不保证给出的图没有重边

image

匈牙利算法

image

几个数组含义:

vis[]: 对于每个左边集合的点 每次清空vis[] 标记右边集合的点是否访问过 防止重复访问
match[]: 右边集合的每个点 匹配的左边集合的点
算法

核心思想

如果i没有匹配对象 或者 i的匹配对象v可以找到另外的匹配对象 那么x就可以和i匹配

注意不止一个连通块 即 一次染色不一定染完了 所以要遍历1~n 判断col[i]==0?

#include<bits/stdc++.h>
using namespace std;
//二分图最大匹配 匈牙利算法
#define int long long
int n,m,e;
int g[505][505]; 
int vis[505],match[505];//match 记录的是 右边集合匹配的点 
bool find(int x)
{
	for(int i=1;i<=m;i++)
		if(!vis[i]&&g[x][i])//如果存在边 且 没有标记过
		{
			vis[i]=1;//标记防止重复访问 
			int v=match[i];
			if(v==0||find(v))//如果i没有匹配对象 或者 i的匹配对象v可以找到另外的匹配对象
							// 那么x就可以和i匹配
			{
				match[i]=x;
				return true;//x找到了匹配对象 
			}
		}
	return false;//x没找到匹配对象
}
signed main()
{
	ios::sync_with_stdio(false);
	cin>>n>>m>>e;
	for(int i=1;i<=e;i++)
	{
		int u,v;
		cin>>u>>v;
		g[u][v]=1;
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		memset(vis,0,sizeof(vis));
		if(find(i))ans++;
	}
	cout<<ans<<"\n";
	return 0;
}
posted @ 2023-04-14 20:45  N0zoM1z0  阅读(3)  评论(0编辑  收藏  举报