图的匹配
【概念】
都是无向图的概念
-
支配集:一个点集,使得无向图中每个点要么是点集中的点,要么与点集相邻。
-
独立集:一个点集,使得点集中任意两点不相邻。
以上两个在任意图中都是 NP 问题,也就是无法在多项式时间内求解的问题。
- 点覆盖:一个点集,使得所有边都至少与点集中一个点相连。
结论:点覆盖的补集是独立集,独立集的补集也是点覆盖。
证明:若点覆盖的补集里存在一条边连接,说明这条边没覆盖;而所有边肯定不可能两端都属于独立集,所以独立集的补集一定覆盖了所有边。
推论:最小点覆盖
-
边覆盖:一个边集,使得所有点都有其中的邻边。(有孤立点则不存在边覆盖)
-
匹配:一些不重合的点对,点对之间有边。(注意有的点可能没有被选)
-
最大匹配:所有匹配中点对数量最多是多少
结论:最小边覆盖 = 最大匹配
证明(感性):最小边覆盖每次尽量选连接两个新点的边,这就是找最大匹配。
由这个结论,我们只要求出最大匹配,就能求出最小边覆盖。
【支配集(没啥用)】
- 图的结点分为支配集
与补集 ,则 中点必然与 中某一个点相邻。
-
极小支配集:该支配集删除任意一个点,都不再是支配集。
-
最小支配集:点最少的支配集。
定理
-
不与 中其他点相邻。 -
存在
,使 是 的唯一 中邻点。
定理
定理
【匹配】
- 选
对相邻的结点,无公共点。求最大的 。
因为一般图匹配困难一些,先说二分图。
【二分图/二部图】
可以把
二分图判定:染色法。
【二分图最大匹配】
- 无权,求最大匹配数。
法一:最大流 Dinic,
Dinic 的缺点是难写、不容易做拓展;优点是快。
为什么复杂度
-
先进行
轮找增广路。每轮 。共 。为什么每次是
?这是因为边容量全是 ,故每条边都只会在某增广路中贡献一次操作,所以总复杂度贡献是 。 -
再在残余网络上找增广路,每次增加
流量。我们要说明距离找完所有增广路,最多还需要 次,共 。注意网络流里流了一条
的边,就相当于匹配了这两个点。设我们此时 匹配了的边的集合是 ,某最大匹配的匹配边集是 。结论:
中的边形成了若干条锯齿状的路径。(不可能有点的度
,否则抽屉原理在 或 中存在一个点的度 ,就不是匹配了)下证:剩余的增广路
条。证明:因为已经做了
轮 Dinic,所以剩下的增广路长度必然 ……(待补)
法二:匈牙利算法,
有一些概念:
-
交替路径:轮换经过匹配边/非匹配边的路径。
-
增广路:起止点都是非匹配点的交替路径。
依次访问
-
成功找到增广路,则使增广路上所有边的匹配情况取反;
-
失败,则跳过。
bool srh(int x) {
for (int j = 0; j < e[x].size(); j++)
if (!vis[e[x][j]]) {
vis[e[x][j]] = true;
if (mc[e[x][j]] == -1 || srh(mc[e[x][j]])) {
mc[e[x][j]] = x, tw[x] = e[x][j];
return true;
}
}
return false;
}
这里面
Q:为什么 if
后面不用 vis[e[x][j]] = false
?
A:因为它现在就找不到增广路,以后更找不到增广路,可以直接 vis = true
避免重复访问。
true
并全部取反;否则返回 false
。
匈牙利算法的缺点是慢;优点是好写、容易拓展。(比如我们只用匹配到中间的结果就行了,可以用匈牙利算法)
【最小点覆盖】
有一种求最小点覆盖的方法:
网络流,建立超源点
求最小割就是答案。因为对于每一条
复杂度:
【柯尼希定理】
二分图最小点覆盖 = 最大匹配。(无权)
所以可以直接求最大匹配,然后得到最小点覆盖,再 n - 最小点覆盖得到最大独立集。
【带权】
带权之后,最大匹配和最小点覆盖就不同了。但是最小点覆盖和最大独立集还是可以互相转化。
【带权二分图最小点覆盖】
最小点权和最小点数点覆盖
把网络流求最小点覆盖中,
求最小割。
复杂度:上限
如果有负权点:肯定是先把所有负权点选了,然后看每一条边有没有覆盖到。把所有没覆盖到的边用网络流做。
最大点权和最小点数点覆盖
把所有点权取反,就变成上一种情况了。
【二分图带权匹配】
先保证匹配最大,再保证权值。
有点权:把每条边的权设定为两端的点权之和,变成有边权的情况。
有边权:
-
费用流。中间的边的费用设定为边权,
和 的边费用为 ,容量和不带权的一样,跑最大/小费用最大流。复杂度最差
,因为增广路长度最多 ,所以最多分 次层;一轮增广 ;最大流 可以视为 。 -
KM 算法:
。但注意,KM 的 经常跑满,有时候还没有费用流快。解决完美匹配问题。对每个结点进行标号
,使得 。(一定可以做到,因为可以赋值为无穷大) 的边 称为相等边或紧边。当所有匹配边紧时,达到最大匹配。答案为
。记原图为 ,当前的紧边构成图 。因为
,故取相等时, 取最大。记左集为 ,右集为 。-
首先
,令 为 邻边最大权; ,令 。 -
对于
,依次:-
若
在 中未匹配,则从 出发搜 的交错路并打标记。 -
判断有无增广路。
-
若有,增广结束(让
匹配上);无,调整 。怎么调整 ?记
为 中标记点, 为 中无标记点, 为 中标记点。(这里的标记是上面交错路标记)不断重复这个过程,直到从
出发能找到一条增广路(直到从 出发能在 中找到一个匹配的点):找到 最小值 ,然后对所有 。显然这么做了之后,紧边仍然紧,而且至少让一条松边紧了。
-
-
【一般图最大匹配】
开花树算法(Blossom)
二分图当且仅当无奇环,开花树算法对奇环做了处理。
这里的“花”就是奇环。
因为奇环没法处理,直接把奇环缩点。原本连到奇环上的
原图存在增广路,当且仅当缩图存在增广路。
【题目】
稳定婚姻
教练曰:美国就变成一般图匹配,甚至自我匹配了。
就是二分图,注意夫妻之间没有连边。
初始让每个女人
复杂度
变换序列
简化题意:
定义
我们构造一个二分图:若
显然当要求
但问题是:怎么保证字典序最小?
考虑一个中间结果:不妨假设此时
因为
接下来考虑尽量让
如果真的匹配上了,因为字典序是贪心的,直接将
当然如果
整个算法流程:先跑一个二分图匹配,然后挨个尝试变小。
复杂度是多少?
对于每个点,我们会从小到大枚举它所有邻边,尝试让那个失配的点找增广路。上面说了,一个点最多两条边,而找增广路是
所以总复杂度是
小行星
建立一个二分图:左右各
因为左边
线段
把横向、纵向的线段作为二分图的左右两边。有交点的线段相互连边。
求最大独立集 = n - 最小点覆盖 = n - 最大匹配。
骑士共存问题
把每个格子抽象为结点,可以相互攻击的结点连边。
为什么是二分图?因为国际象棋棋盘黑白染色。
然后求最大独立集。
考虑用染色方法构建二分图。
长脖子鹿放置
染色方法(证明是二分图的方法):一行一种颜色。
方格取数问题
每个格子抽象为结点,相邻格子代表的结点连边,点权是格子上的数。求最大点权和独立集。
用 sum - 最小点权和点覆盖 求。
太空飞行计划
左半边点代表实验,右半边点代表仪器。
右半边点向
一个实验
考虑最小割,对于一个到
-
若是代表实验的点,代表不做这个实验。
-
若是代表仪器的点,代表买这个仪器。
每个边割了,都是负收益。
这么做的意义是什么:对于一条
然后用所有实验的总收益减去最小割。
怎么理解?对于实验
最后的问题:怎么求最小割?
注意不能检查每条边的容量,因为最大流流过去,一条增广路上随便选一条边都有可能。
设最小割为
复杂度
Card Game
二分等级。
每张卡片抽象为一个结点,魔力值和为质数的卡片之间连边。
尝试让二分图的左右两边代表魔力值为奇/偶的卡片。如果是“和不能为奇质数”,就是二分图;但可惜现在不是。
如果和为
然后构建二分图,点权是卡片的能量,求最大权独立集。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!