图的匹配

【概念】

都是无向图的概念

  • 支配集:一个点集,使得无向图中每个点要么是点集中的点,要么与点集相邻。

  • 独立集:一个点集,使得点集中任意两点不相邻。

以上两个在任意图中都是 NP 问题,也就是无法在多项式时间内求解的问题。

  • 点覆盖:一个点集,使得所有边都至少与点集中一个点相连。

结论:点覆盖的补集是独立集,独立集的补集也是点覆盖。

证明:若点覆盖的补集里存在一条边连接,说明这条边没覆盖;而所有边肯定不可能两端都属于独立集,所以独立集的补集一定覆盖了所有边。

推论:最小点覆盖 最大独立集。

  • 边覆盖:一个边集,使得所有点都有其中的邻边。(有孤立点则不存在边覆盖)

  • 匹配:一些不重合的点对,点对之间有边。(注意有的点可能没有被选)

  • 最大匹配:所有匹配中点对数量最多是多少

结论:最小边覆盖 = 最大匹配 k+没有在匹配中选到的点的数量 n2k

证明(感性):最小边覆盖每次尽量选连接两个新点的边,这就是找最大匹配。

由这个结论,我们只要求出最大匹配,就能求出最小边覆盖。

【支配集(没啥用)】

  • 图的结点分为支配集 U 与补集 V,则 V 中点必然与 U 中某一个点相邻。
  1. 极小支配集:该支配集删除任意一个点,都不再是支配集。

  2. 最小支配集:点最少的支配集。

定理 U 为极小支配集,当且仅当对 U 中任意一个点 u 有如下条件,至少一个成立。

  1. u 不与 U 中其他点相邻。

  2. 存在 vV,使 uv 的唯一 U 中邻点。

定理 若无孤立点,极小支配集的补集也是支配集。

定理 最小支配集大小 n2

【匹配】

  • k 对相邻的结点,无公共点。求最大的 k

因为一般图匹配困难一些,先说二分图。

【二分图/二部图】

可以把 G=(V,E)V 分成两个点集 A,B,使 E 中的边两端都分属 A,B 的图。

二分图判定:染色法。

【二分图最大匹配】

  • 无权,求最大匹配数。

法一:最大流 Dinic,O(mn)

Dinic 的缺点是难写、不容易做拓展;优点是快。

S 向左半边连 1 边,右半边向 T1 边,左右之间的边流量都取 1。最大流就是最大匹配数。

为什么复杂度 O(mn)?下面证明。(还没补)

  1. 先进行 O(n) 轮找增广路。每轮 O(m)。共 O(mn)

    为什么每次是 O(m)?这是因为边容量全是 1,故每条边都只会在某增广路中贡献一次操作,所以总复杂度贡献是 O(m)

  2. 再在残余网络上找增广路,每次增加 1 流量。我们要说明距离找完所有增广路,最多还需要 O(n),共 O(mn)

    注意网络流里流了一条 AB 的边,就相当于匹配了这两个点。设我们此时 A,B 匹配了的边的集合是 P,某最大匹配的匹配边集是 Q

    结论:P,Q 中的边形成了若干条锯齿状的路径。

    (不可能有点的度 3,否则抽屉原理在 PQ 中存在一个点的度 2,就不是匹配了)

    下证:剩余的增广路 n 条。

    证明:因为已经做了 n 轮 Dinic,所以剩下的增广路长度必然 n ……(待补)


法二:匈牙利算法,O(mn)。(不如 Dinic 呢 ~)

有一些概念:

  • 交替路径:轮换经过匹配边/非匹配边的路径。

  • 增广路:起止点都是非匹配点的交替路径。

依次访问 A 中点 i,尝试对 i 找增广路。

  1. 成功找到增广路,则使增广路上所有边的匹配情况取反;

  2. 失败,则跳过。

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;
}

这里面 mc[x] 表示 xB 当前的匹配点,tw[x] 表示 xA 当前的匹配点。如果是 1 表示当前没匹配。

Q:为什么 if 后面不用 vis[e[x][j]] = false

A:因为它现在就找不到增广路,以后更找不到增广路,可以直接 vis = true 避免重复访问。

srh(x) 表示从 xA 出发,判断是否存在一条交替路径,如果存在,返回 true 并全部取反;否则返回 false

匈牙利算法的缺点是慢;优点是好写、容易拓展。(比如我们只用匹配到中间的结果就行了,可以用匈牙利算法)

【最小点覆盖】

有一种求最小点覆盖的方法:

网络流,建立超源点 S,向每个 iA 连容量 1 的边;建立超汇点 T,每个 iBT 连容量为 1 的边;原本存在的边设置流量为 +

求最小割就是答案。因为对于每一条 + 边,两端一定有被割掉的,所以就是一个点覆盖。

复杂度:O(mn)

【柯尼希定理】

二分图最小点覆盖 = 最大匹配。(无权

所以可以直接求最大匹配,然后得到最小点覆盖,再 n - 最小点覆盖得到最大独立集。

【带权】

带权之后,最大匹配和最小点覆盖就不同了。但是最小点覆盖和最大独立集还是可以互相转化。

【带权二分图最小点覆盖】

最小点权和最小点数点覆盖

把网络流求最小点覆盖中,s 向左边连的边 以及 右边向 t 连的边 的容量 设为点权。

求最小割。

复杂度:上限 O(nm)

如果有负权点:肯定是先把所有负权点选了,然后看每一条边有没有覆盖到。把所有没覆盖到的边用网络流做。

最大点权和最小点数点覆盖

把所有点权取反,就变成上一种情况了。

【二分图带权匹配】

先保证匹配最大,再保证权值。

有点权:把每条边的权设定为两端的点权之和,变成有边权的情况。

有边权:

  1. 费用流。中间的边的费用设定为边权,st 的边费用为 0,容量和不带权的一样,跑最大/小费用最大流。

    复杂度最差 O(n2m),因为增广路长度最多 m,所以最多分 m 次层;一轮增广 O(n);最大流 f 可以视为 n

  2. KM 算法:O(n3)。但注意,KM 的 O(n3) 经常跑满,有时候还没有费用流快。解决完美匹配问题

    对每个结点进行标号 lab,使得 labu+labvw(u,v)。(一定可以做到,因为可以赋值为无穷大)

    labu+labv=w(u,v) 的边 (u,v) 称为相等边或紧边。

    当所有匹配边紧时,达到最大匹配。答案为 lab。记原图为 G,当前的紧边构成图 G

    因为 labw,故取相等时,w 取最大。记左集为 U,右集为 V

    1. 首先 uU,令 labuu 邻边最大权;vV,令 labv=0

    2. 对于 u1,u2,,unU,依次:

      • uG 中未匹配,则从 u 出发搜 G 的交错路并打标记。

      • 判断有无增广路。

      • 若有,增广结束(让 u 匹配上);无,调整 lab。怎么调整 lab

        xU 中标记点,yV 中无标记点,kV 中标记点。(这里的标记是上面交错路标记)

        不断重复这个过程,直到从 u 出发能找到一条增广路(直到从 u 出发能在 G 中找到一个匹配的点):找到 labx+labyw(x,y) 最小值 d,然后对所有 labx=d,labk+=d。显然这么做了之后,紧边仍然紧,而且至少让一条松边紧了。

【一般图最大匹配】

开花树算法(Blossom)

二分图当且仅当无奇环,开花树算法对奇环做了处理。

这里的“花”就是奇环。

因为奇环没法处理,直接把奇环缩点。原本连到奇环上的

原图存在增广路,当且仅当缩图存在增广路。

【题目】

稳定婚姻

教练曰:美国就变成一般图匹配,甚至自我匹配了。

就是二分图,注意夫妻之间没有连边。

初始让每个女人 i 的初始匹配都是男 i。然后枚举男 i,尝试找增广路,如果找到了就不安全。

复杂度 O(nm)

变换序列

简化题意:

定义 d(x,y)=min(|xy|,n|xy|)。要求构造一个字典序最小的长度 n 的序列 Ti,使得 d(i,Ti) 刚好是给定的 di。(或者输出不存在)n104

我们构造一个二分图:若 d(i,x)=di,则令 iAxB 连一条边。问题就是求是否存在完美匹配。

显然当要求 d(i,x)=di 时,至多有两个 x 满足,所以复杂度可以接受。

但问题是:怎么保证字典序最小?

考虑一个中间结果:不妨假设此时 (0,T0=1),(1,T1=2) 已经匹配好了,且是最小的使得后面能匹配的匹配

因为 T0,T1 已经确定,后面改了肯定不优,我们直接锁定 T0,T1,后面干什么都不能动。

接下来考虑尽量让 T2 小。令 T2 尝试匹配尽可能小的,记作 t。此时我们只需要检查哪个原本匹配 t 的 失配了,是否还能找到增广路,就能判断 T2 能否可以 =t

如果真的匹配上了,因为字典序是贪心的,直接将 T2 锁定为 t

当然如果 T2 配不了 t,就检查 t 更大的。

整个算法流程:先跑一个二分图匹配,然后挨个尝试变小。

复杂度是多少?

对于每个点,我们会从小到大枚举它所有邻边,尝试让那个失配的点找增广路。上面说了,一个点最多两条边,而找增广路是 O(m) 的,所以对于一个点是 O(m) 的,在这题里,也就是 O(2n)=O(n) 的。

所以总复杂度是 O(n2) 的,当然这只是理论上限,实际上根本跑不满。

小行星

建立一个二分图:左右各 n 个点,分别表示 nn 列。对于一个小行星 (x,y),则左边 x 和右边 y 之间连边。然后求最小点覆盖(最大匹配)即可。

因为左边 x 和右边 y 连边,就要求了 x,y 中必须选一个,对应了一颗小行星要么被行消除要么被列消除。

线段

把横向、纵向的线段作为二分图的左右两边。有交点的线段相互连边。

求最大独立集 = n - 最小点覆盖 = n - 最大匹配。

骑士共存问题

把每个格子抽象为结点,可以相互攻击的结点连边。

为什么是二分图?因为国际象棋棋盘黑白染色。

然后求最大独立集。

考虑用染色方法构建二分图。

长脖子鹿放置

染色方法(证明是二分图的方法):一行一种颜色。

方格取数问题

每个格子抽象为结点,相邻格子代表的结点连边,点权是格子上的数。求最大点权和独立集。

用 sum - 最小点权和点覆盖 求。

太空飞行计划

左半边点代表实验,右半边点代表仪器。

s 向左半边点连边,容量为这个实验的收益。

右半边点向 t 连边,容量为这个仪器的花费。

一个实验 u 向它所需的所有仪器连边,容量为 +

考虑最小割,对于一个到 s(或 t) 的边被割的点:

  1. 若是代表实验的点,代表不做这个实验。

  2. 若是代表仪器的点,代表这个仪器。

每个边割了,都是负收益。

这么做的意义是什么:对于一条 + 边,连 (i,j) 两点:代表要么不做实验 i,要么买仪器 j

然后用所有实验的总收益减去最小割。

怎么理解?对于实验 i 和仪器 j,只有(要做 i 但是不买 j)这一种情况是矛盾的,于是用 + 的边代表这个矛盾。

最后的问题:怎么求最小割?

注意不能检查每条边的容量,因为最大流流过去,一条增广路上随便选一条边都有可能。

设最小割为 C,枚举每一个点,先把它到 s/t 的容量变成 0,跑最小割。看一下最小割是否是 Cw:如果是,则必存在一个最小割方案,删除了这个点;如果更大,则恢复这条边到原来的容量。

复杂度 O(nm×n)

Card Game

二分等级。

每张卡片抽象为一个结点,魔力值和为质数的卡片之间连边。

尝试让二分图的左右两边代表魔力值为奇/偶的卡片。如果是“和不能为奇质数”,就是二分图;但可惜现在不是。

如果和为 2,一定是 1+1,我们尝试特判这种情况:所有 1 魔力值的结点只留一个能量最大的。

然后构建二分图,点权是卡片的能量,求最大权独立集。

posted @   FLY_lai  阅读(68)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示