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

本文详细介绍了匈牙利算法在二分图匹配问题中的操作流程,通过女友版示例和洛谷题目实例,展示了如何使用女孩数组和配对标志来求解最大匹配边数。算法核心在于交替路径匹配,时间复杂度为O(n×e+m)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

常用的二分图匹配算法是匈牙利算法,匈牙利算法的过程是,枚举每一个左部点 u ,然后枚举该左部点连出的边,对于一个出点 v,如果它没有被先前的左部点匹配,那么直接将 u 匹配 v,否则尝试让 v 的“原配”左部点去匹配其他右部点,如果“原配”匹配到了其他点,那么将 u 匹配 v,否则 u 失配。尝试让 “ 原配 ” 寻找其他匹配的过程可以递归进行。需要注意的是,在一轮递归中,每个右部点只能被访问一次。算法的时间复杂度为 O(n×e+m),其中 n 是左部点个数,e 是图的边数,m 是右部点个数。
匈牙利算法分女友版通俗易懂的讲解:

https://blog.youkuaiyun.com/Dark_Scope/article/details/8880547?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-3.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-3.control

因为这个解析,导致本人写的匹配数组都是girl[],OwO
模板题目洛谷P3386

https://www.luogu.com.cn/problem/P3386

题目描述
给定一个二分图,其左部点的个数为 n,右部点的个数为 m,边数为 e,求其最大匹配的边数。
左部点从 1 至 n 编号,右部点从 1 至 m 编号。
输入格式
输入的第一行是三个整数,分别代表 n,m 和 e。
接下来 e 行,每行两个整数 u,v,表示存在一条连接左部点 u 和右部点 v 的边。
输出格式
输出一行一个整数,代表二分图最大匹配的边数。
输入输出样例
输入 #1
1 1 1
1 1
输出 #1
1
输入 #2
4 2 7
3 1
1 2
3 2
1 1
4 2
4 1
1 1
输出 #2
2
说明/提示
数据规模与约定
对于全部的测试点,保证:
1≤n,m≤500。
1≤e≤5×104
1≤u≤n,1≤v≤m
不保证给出的图没有重边。

放上模板统计配对的数目输出即可:

#include<iostream>
#include<cstdio>
#include<memory.h>
using namespace std;
const int MAXN=550;
const int MAXM=550;
int n,m,e;
bool line[MAXN][MAXM],use[MAXM];
int girl[MAXM];

bool find(int x)
{
	for(int i=1;i<=m;i++)
	{
		if (line[x][i]&&!use[i])
		{
			use[i]=true;
			if (girl[i]==0||find(girl[i]))
			{
				girl[i]=x;
				return true;
			}
		}
	}
	return false;
}

int main()
{
	scanf("%d%d%d",&n,&m,&e);
	for(int i=1,u,v;i<=e;i++)
	{
		scanf("%d%d",&u,&v);
		line[u][v]=true;
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		memset(use,false,sizeof(use));
		if(find(i))
			ans++;
	}
	printf("%d\n",ans);
	return 0;
} 

模板题2:洛谷P2319

链接:https://www.luogu.com.cn/problem/P2319

题目与第一题一样,除了数据范围不一样,有一点注意,当选手答错时要直接break掉,因为只有答对上一题才能继续往下继续答题。

AC代码:

#include<iostream>
#include<cstdio>
#include<memory.h>
using namespace std;
const int MAXN=1005;
const int MAXM=1005;
int n,m;
bool line[MAXM][MAXN],use[MAXN];
int girl[MAXN];

bool find(int x)
{
	for(int i=0;i<n;i++)
	{
		if (line[x][i]&&!use[i])
		{
			use[i]=true;
			if (girl[i]==0||find(girl[i]))
			{
				girl[i]=x;
				return true;
			}
		}
	}
	return false;
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1,a,b;i<=m;i++)
	{
		scanf("%d%d",&a,&b);
		line[i][a]=true;
		line[i][b]=true;
	}
	int ans=0;
	for(int i=1;i<=m;i++)
	{
		memset(use,false,sizeof(use));
		if(find(i))
			ans++;
		else break;
	}
	printf("%d\n",ans);
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值