专栏文章
题解:P3386 【模板】二分图最大匹配
P3386题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mipc7tq2
- 此快照首次捕获于
- 2025/12/03 09:37 3 个月前
- 此快照最后确认于
- 2025/12/03 09:37 3 个月前
P3386 【模板】二分图最大匹配 题解
1. 引入:
First . 二分图:
既然要学习二分图最大匹配,肯定先要了解啥是二分图。
OI wiki 上说:
二分图是什么?节点由两个集合组成,且两个集合内部没有边的图。换言之,存在一种方案,将节点划分成满足以上性质的两个集合。
就是把一个图上的点分成两组,每一条边都连接不同组的点。
在图中表示为每一条边都从 组的点连到 组的点,不会从 组的点连到 组的点。
second . 二分图匹配:
首先了解二分图匹配(来自 OIwiki):
在图论中,假设图 。其中 是点集, 是边集。一组两两没有公共点的边集 称为这张图的匹配。定义匹配的大小为其中边的数量 ,其中边数最大的 为 最大匹配。
啥意思?
当年的我看见这条定义觉得同样很懵。
那我们不管普通的图,只考虑二分图。
其实就是:
好多条无公共端点的边的集合叫这张二分图的一个匹配。(这里因为是二分图,所以边已经是连接两组点集 , 的了,不需要加以限制)匹配的大小为边的数量。
了解二分图匹配之后,就可以学习二分图最大匹配了。
third . 二分图最大匹配:
顾名思义,就是二分图的所有匹配中边数最多的那个匹配。
OI wiki 同样给出定义:
假设图有 个顶点, 条边。给定一个二分图 G,要求选出一些边,使得这些边没有公共顶点,且边的数量最大。
本题的目的就是实现这个要求。
下面开始讲算法思路。
2. 思路:
准备
本题的解法为匈牙利算法。
首先我们有一张二分图:

随便连上几条边:

算法过程:
先将 号点连接到可以连接的第一个点即 号。然后将 号点连接到可以连接的第一个点即 号。接着连接 号点,但此时我们发现 号点应该连接的 号被 号占用了。 这时,我们将 号点与 号点间的连接断开。这时发现 号点和 号点同时连接到了 号点,与二分图最大匹配的定义不符,所以再为 号点重新连接到 号点。于是就可以把 号点与 号点连接起来了。再往后的 号点应连接到的 号点被占用,无法连接,算法结束。 最大匹配值即为已连接上的边的数量。
注意:匈牙利算法求解的结果中,匹配的边的数量一定为最大,但匹配方式不唯一。
3. 证明:
我们定义:
交错路:始于非匹配点由匹配边于非匹配边交错而成的路径。增广路:始于非匹配点且终于非匹配点(除了起始的点)的交错路。增广路中边的数量是奇数。
根据增广路定义可知:
推论 1. 增广路中匹配边数量比非匹配边数量少一。
通过这两条定义,联系算法过程,不难发现:
- 在匈牙利算法中,我们通过寻找每个未匹配点的增广路来增加匹配数量。
- 匈牙利算法结束时意味着没有增广路了。
所以,要证明:
匈牙利算法得到的匹配为这个二分图的最大匹配。
就被转换成了:
二分图的最大匹配中不存在增广路。
直接证不好证,采用反证法。
即证明:
二分图的最大匹配中有增广路。
不成立。
证明:
假设二分图最大匹配中有增广路:则根据推论 1,我们将图中匹配边与非匹配边反转后,得到一个新的匹配。原非匹配边反转成了匹配边,此时相当于匹配边 。所以,此时原图中存在更大的匹配。故原命题不成立。证毕。
所以:匈牙利算法得到的匹配为这个二分图的最大匹配。
接下来是代码,结合上面文章内容理解应该很简单。
4.Code:
vector 存边,深搜跑算法,重新连接的条件很重要。
CPP#include<iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn = 1005;
int n, m, t;
int mch[maxn], vistime[maxn];
vector<int> e[maxn];
bool dfs(const int u, const int tag);
int main() {
scanf("%d %d %d", &n, &m, &t);
for (int u, v; t; --t) {
scanf("%d %d", &u, &v);
e[u].push_back(v);
}
int ans = 0;
for (int i = 1; i <= n; ++i) if (dfs(i, i)) {
++ans;
}
printf("%d\n", ans);
}
bool dfs(const int u, const int tag) {
if (vistime[u] == tag) return false;
vistime[u] = tag;
for (auto v:e[u]) if ((mch[v] == 0) || dfs(mch[v], tag)) {
mch[v] = u;
return true;
}
return false;
}
全文完。
5. 参考资料:
- OIWiKi。
- Loi23 级学长课件。
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...




