【洛谷】P3386 【模板】二分图最大匹配
洛谷专栏:模板,图论
洛谷模板:P3386 二分图最大匹配
算法竞赛:图论,二分图,二分图最大匹配
匹配算法:匈牙利算法
题目链接:洛谷 P3386
题目描述
给定一个二分图,其左部点的个数为 n n n,右部点的个数为 m m m,边数为 e e e,求其最大匹配的边数。
左部点从 1 1 1 至 n n n 编号,右部点从 1 1 1 至 m m m 编号。
二分图介绍
二分图是节点由两个集合组成,且两个集合内部没有边的图。即存在一种方案,将节点划分成满足以上性质的两个集合。
二分图相关基础知识可以参见 OI-WIKI。
二分图匹配
在二分图中选出一些边作为一个集合,使任意两条边不存在公共点,称为二分图匹配。
在一个二分图中使选出的边数最大的匹配,称为二分图的最大匹配。
匈牙利算法
匈牙利算法是找二分图的最大匹配的经典算法。下面介绍匈牙利算法的步骤与思路和正确性证明。
算法步骤
- 我们通常将二分图存为一张有向图,通常存为从左部的点出发连向右部的点的边。
- 遍历每个左部顶点,并每次都将全部右部顶点设为未标记,(标记 1 1 1,见下条)在每个左部顶点中遍历其出边,如果其相连的右部顶点未被标记,则将其标记,判断其是否被其它左部顶点选中或能否取消被选中(见下条),如果没有被选中或能被取消选中,则被现左部顶点选中,并在最大匹配计数中加一。
- 递归函数——判断右部顶点能否被取消选中。函数步骤即从第二条(标记 1 1 1)处开始,判断右部顶点能否被取消选中即看和这个右部匹配的左部顶点能否与其他右部顶点匹配,让出现在这个右部顶点。
算法思路
从与左部顶点相连的右部顶点中选出能与左部顶点匹配的点,如果能相匹配则立刻选上,但比如有的左部顶点与两个右部顶点相连,第二个左部顶点只与其中一个右部顶点相连,最大匹配则为二,然而如果第一个左部顶点与两个共同所连的右部顶点相匹配,则匹配数就为一了,显然不正确,那么就需要在第二个左部点选右部点的时候看看第一个左部点能否选其他点,从而把公用相连的右部顶点让出来使第二个左部点与之匹配,这样使匹配数最大,如果不能让出来,便就此作罢。
正确性证明
- 模拟证明
- 增广路径证明(现无)
模拟算法过程
见下图。
1 7
1 5
3 7
3 2
4 8
4 2
6 5
6 2
- 从第一个点遍历,点 1 1 1 匹配到点 7 7 7。
- 第二个点 3 3 3 要匹配点 7 7 7,点 1 1 1 可以重匹配点 5 5 5,则点 3 3 3 匹配点 7 7 7。
- 点 4 4 4 匹配到点 2 2 2。
- 点 6 6 6 要匹配点 5 5 5,点 5 5 5 被点 1 1 1 占着且不能被让出,则点 6 6 6 要匹配点 2 2 2,虽然点 2 2 2 被点 4 4 4 占着,但点 4 4 4 可以重匹配到点 8 8 8,让出点 2 2 2 使点 6 6 6 与之匹配。
则这张二分图最大匹配数为 4 4 4。
我们可以把二分图匹配时遇到的所有情况列出来,分析每种情况是否可行即可。
情况一:
显然做法正确。
情况二:
根据上述过程模拟来看也是正确的。
情况三:(上述两种情况的组合体)
根据上述过程模拟来看这种情况下算法也是正确的,由这种情况可得知拆分或组合二分图不会影响算法正确性。
其余所有情况都可以转化、化简、拆分为上述前两种情况。
综上此做法正确。
下面给出完整 AC 代码。
#include <bits/stdc++.h>
using namespace std;
const int N = 510;
vector<int>G[N];
int march[N];
bool ins[N];//标记右部点
bool make(int x)
{
for (int y: G[x])//遍历出边
{
if (!ins[y])
{
ins[y]=true;//标记
if (march[y]==0||make(march[y]))//没有被标记或者能被让出来
{
march[y]=x;//右部点 y 是被左部点 x 标记的
return true;
}
}
}
return false;
}
int main()
{
int n1,n2,m,ans=0;
scanf("%d%d%d",&n1,&n2,&m);
for (int i=0;i<m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
G[x].push_back(y);//存有向图
}
for (int i=1;i<=n1;i++)
{
memset(ins,0,sizeof ins);//取消标记
if (make(i)) ans++;
}
printf("%d",ans);
return 0;
}
End
感谢观看,如有问题欢迎指出。
更新日志
- 2025/8/19 开始书写本篇 CSDN 博客,并完稿发布。
本篇博客最早由本人发布于洛谷文章广场,本篇博客对其进行了修改调整与完善丰富。