想象你是公司里的「团建活动总导演」,要把同事们两两组队参加双人项目。规则只有一条:每个人只能出现在一支队伍里。你的目标是用有限的人,组建出尽可能多的队伍。这正是图论中「匹配」问题的原型——把人与人之间的合作意愿看成边,把「不冲突的组队方案」看成匹配,而「最多能组几队」就是最大匹配。 不过事情没那么简单。光靠「先到先得」抢人,往往拿不到最优方案;有时为了多组一队,还得拆散已经组好的队伍重新洗牌。这背后藏着一套精妙的「增广路径」理论。顺着这条线索,我们会认识专门解决男女配对问题的匈牙利算法、追求总收益最大化的KM算法,以及连「三角恋死循环」都能处理的Blossom开花算法。读完这篇文章,你会像一位经验丰富的总导演一样,一眼看出最优组队方案,还能把这个能力迁移到任务指派、资源调度的真实场景中。

岗位关联

图匹配是组合优化与网络算法的基石工具。掌握最大匹配与最优匹配的求解思想,是AI从业者把抽象图模型落地为调度、指派、推荐等现代系统优化方案的核心能力。

目录
  1. 可视化演示
  2. 匹配定义与性质
  3. 增广路径定理
  4. 匈牙利算法
  5. KM最优匹配
  6. Blossom奇环
  7. 匹配应用场景
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示图匹配三大核心:二部图匹配、增广路径交替路、Kuhn-Munkres最优权匹配,通过动态网络图演示匹配过程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

二部图最大匹配 左右两侧节点寻找一一对应关系 绿色边为已匹配边,粒子沿匹配流动 匈牙利算法核心

匹配定义与性质

团建总导演的第一件事,是搞清楚什么叫「合格」的组队方案。假如同事之间有6条合作意愿边,你不可能全安排——因为每个员工分身乏术。合格的方案只能挑出一些边,保证「没有两条边共用同一个人」。这就是匹配的本质:从边集中挑出互不打架的边。

在数学上,图 \( G=(V,E) \) 的一个匹配 \( M \),就是满足「任意两条边都没有公共端点」的边集。最大匹配是边数最多的匹配,完美匹配则是让每个顶点都被匹配边覆盖的匹配——相当于所有人都组上了队,一个不落。注意,不是所有图都有完美匹配,正如不是每次团建都能全员上阵。

M={e1,e2,…,ek}⊆E,ei∩ej=∅ (∀i≠j),∣M∣≤⌊∣V∣2⌋\displaystyle M=\{e_1,e_2,\ldots,e_k\}\subseteq E,\qquad e_i\cap e_j=\varnothing\ (\forall i\neq j),\qquad |M|\le \left\lfloor\frac{|V|}{2}\right\rfloor

1. 边集选取:匹配 \( M \) 是从原图所有边中挑出的一个子集

M⊆E\displaystyle M\subseteq E

2. 两两不相交:任意两条匹配边 \( e_i \) 与 \( e_j \) 没有公共端点,用交集为空表示

ei∩ej=∅\displaystyle e_i\cap e_j=\varnothing

3. 边数上界:每条边消耗2个顶点,所以匹配边数最多是顶点数的一半

∣M∣≤⌊∣V∣2⌋\displaystyle |M|\le \left\lfloor\frac{|V|}{2}\right\rfloor

回到团建:匹配是「每人只参与一队」的纪律,最大匹配是「在不违反纪律的前提下组出最多队伍」,而完美匹配是「全体成员都找到了队伍」。理解了这个基础,接下来要解决的关键问题就是:如何系统性地让队伍数量一步步逼近上限。

增广路径定理

现在的组队方案是 \( M \)(比如2队),你想再塞进一队,但所有人都已经被安排了。总导演的经验是:不要硬抢,试着让两对组合「串一串」。比如小张和小李搭档、小王和小赵搭档,如果小张其实更想和小赵搭档,小李又闲着没组上,就能形成一条「换人链」,让整体队伍数量+1。

这条「换人链」在数学上叫增广路径。它是一条路径,边在「非匹配边—匹配边—非匹配边—匹配边」之间交替出现,并且路径的两端都是未匹配顶点。沿着这条路径,把匹配边和非匹配边全部互换——也就是对路径做对称差运算——队伍数量就会增加1。图 \( G \) 的匹配 \( M \) 是最大匹配,当且仅当 \( G \) 中不存在关于 \( M \) 的增广路径。 这就是增广路径定理,整个最大匹配算法的理论基石。

M′=M⊕P=(M∖P)∪(P∖M),∣M′∣=∣M∣+1\displaystyle M' = M \oplus P = (M\setminus P)\cup(P\setminus M),\qquad |M'|=|M|+1

1. 交替特征:路径上的边交替属于 \( M \) 与不属于 \( M \),不能连续两条同为匹配边或同为非匹配边

P=(v0,v1,…,vt),e2i∉M, e2i+1∈M\displaystyle P=(v_0,v_1,\ldots,v_t),\quad e_{2i}\notin M,\ e_{2i+1}\in M

2. 两端空闲:路径的起点 \( v_0 \) 与终点 \( v_t \) 都是未匹配顶点,这是「能新塞一队」的前提

v0,vt∉V(M)\displaystyle v_0,v_t\notin V(M)

3. 对称差操作:把路径上的边全部「取反」——原来的匹配边变为非匹配边,非匹配边变为匹配边

M′=M⊕P\displaystyle M' = M \oplus P

4. 数量加一:路径上非匹配边比匹配边多一条,取反后匹配边总数净增1

∣M′∣=∣M∣+1\displaystyle |M'|=|M|+1

增广路径就像团建排班里的「连锁调整」:只要有人愿意调整搭档,就总能多组一队。而增广路径定理保证了这一策略的完备性——当所有连锁调整都尝试过仍无法新增队伍时,你手里的方案就是全局最优。那么具体如何系统性地找到增广路径呢?这就轮到匈牙利算法登场了。

匈牙利算法

匈牙利算法的思路,像一个「先到先得 + 及时让位」的排班系统。算法从左边的未匹配顶点出发,用深度优先搜索(DFS)或广度优先搜索(BFS)尝试寻找增广路径。每找到一个未匹配的右顶点,就尝试把它占下;如果这个右顶点已经被匹配,就递归地让它的搭档「再去找别的右顶点」,也就是腾位。

这个过程会形成一棵交替搜索树:树的根是未匹配左顶点,往下交替走「非匹配边—匹配边」。如果树中某个未匹配右顶点被探到,就说明找到了一条增广路径;此时沿路径做对称差更新匹配,匹配数+1。对每个左顶点重复这一过程,直到没有增广路径可找。因为每轮增广至少增加一条匹配边,而匹配数上界是 \( \lfloor n/2 \rfloor \),加上DFS本身要遍历 \( O(E) \) 条边,总复杂度为 \( O(VE) \)。

对每个未匹配 u∈X: DFS(u) 找增广路径;找到则 M←M⊕P\displaystyle \text{对每个未匹配 } u\in X:\ \text{DFS}(u)\ \text{找增广路径};\quad \text{找到则 } M\leftarrow M\oplus P

1. 逐一尝试:依次从每个未匹配的左顶点出发,把它当作搜索树的根

u∈X, u∉V(M)\displaystyle u\in X,\ u\notin V(M)

2. 递归腾位:DFS 访问右顶点 \( v \),若 \( v \) 未匹配则找到增广路径;若已匹配给 \( u' \),则递归让 \( u' \) 另寻他路

v∉V(M)⇒增广成功;v∈V(M)⇒DFS(u′)\displaystyle v\notin V(M)\Rightarrow \text{增广成功};\quad v\in V(M)\Rightarrow \text{DFS}(u')

3. 访问标记:每轮 DFS 维护 \( \text{visited} \),避免重复搜索形成死循环

visited[v]=true\displaystyle \text{visited}[v]=\text{true}

4. 匹配数增长:每找出一条增广路径,匹配边数加1,直到不存在增广路径

∣M∣←∣M∣+1\displaystyle |M|\leftarrow |M|+1

匈牙利算法完美继承了增广路径定理的「体检报告」逻辑:每一轮要么找到增广路径让匹配更优,要么证明该顶点已无路可增广。它的局限也很明显——只适用于二部图,因为一旦图中有奇环(如三角形),递归可能陷入同一批顶点的循环。这个坑,要等Blossom算法来填。先把二部图问题彻底解决,我们再谈带权的最优匹配——KM算法。

KM最优匹配

团建总导演渐渐不满足于「队伍最多」——他开始关心总产出:每对搭档合作能创造不同的价值,他希望让总价值最大。这正是最优匹配(带权匹配)问题,Kuhn-Munkres算法(简称KM)是它的经典解法。KM算法的妙招是给每个顶点发一张「能力标价牌」,规则是左顶标 \( l(x) \) 加右顶标 \( l(y) \) 必须不低于两人合作的收益 \( w(x,y) \),这叫可行顶标。

在所有边中,只保留「标价刚好等于收益」的边,这些边组成相等子图。可以证明:若相等子图中存在完备匹配,那么这个匹配一定是最优匹配,且总收益恰好等于所有顶标之和。如果当前相等子图找不到完备匹配,就适当降低某些左顶标、提高某些右顶标,让更多边进入相等子图,直到找到完备匹配为止。KM算法通过反复增广和调整顶标,保证在 \( O(n^3) \) 时间内得到最优解。

l(x)+l(y)≥w(x,y),∀x∈X,y∈Y\displaystyle l(x)+l(y)\ge w(x,y),\quad \forall x\in X, y\in Y

若 Gl 有完备匹配 M∗, 则 ∑e∈M∗w(e)=∑x∈Xl(x)+∑y∈Yl(y)\displaystyle \text{若 } G_l \text{ 有完备匹配 } M^*, \text{ 则 } \sum_{e\in M^*} w(e)=\sum_{x\in X}l(x)+\sum_{y\in Y}l(y)

1. 可行顶标:左顶点 \( x \) 与右顶点 \( y \) 的顶标之和不小于边权,保证顶标是「不虚高」的上界

l(x)+l(y)≥w(x,y)\displaystyle l(x)+l(y)\ge w(x,y)

2. 相等子图:只保留满足 \( l(x)+l(y)=w(x,y) \) 的边

Gl={(x,y):l(x)+l(y)=w(x,y)}\displaystyle G_l=\{(x,y): l(x)+l(y)=w(x,y)\}

3. 完备匹配判定:在相等子图中寻找覆盖所有顶点的完美匹配

M∗ 是 Gl 的完备匹配\displaystyle M^*\text{ 是 } G_l \text{ 的完备匹配}

4. 最优性证明:任意匹配 \( M \) 的总权不超过顶标总和,而 \( M^* \) 恰好达到该和

w(M)≤∑l(v)=w(M∗)\displaystyle w(M)\le \sum l(v)=w(M^*)

KM算法的「标价牌」像相亲节目里的心动值:先给每个人打一个「理想分」,只撮合分数刚好互补的两人;撮合不齐时再微调分数,让更多候选者进入待选池。因为这套标价体系始终锁定了收益的上限,一旦凑齐完备配对,就同时拿到了「人数满员」和「收益最大」的双重最优。不过,无论是匈牙利还是KM,都默认图是二部图——如果同事之间的关系网出现「三角恋」式的奇环,又该怎么办?

Blossom奇环

当图不是二部图时,事情变得棘手。二部图里,每条交替路径从左部出发必然回到右部,永远「黑白分明」;而一般图中的奇环(比如三角形)会让交替搜索树从不同方向探到同一个顶点,迭代陷入死循环——就像团建排班时三个人互相盯上了对方搭档,怎么调整都出不来新方案。

Edmonds在1965年给出了天才解法:把奇环整体收缩成一个「花苞」(Blossom)。奇环内部无论怎么匹配,一定恰好剩一个未匹配顶点(因为奇环顶点数为奇数),所以收缩后用一个超级顶点代替整个环,继续在外层跑增广路径;一旦找到增广路径,再展开花苞、还原环内的匹配细节。这个过程叫开花算法,成功把一般图最大匹配拉回多项式时间。

G′=G/B,ν(G)=ν(G′)+⌊∣B∣2⌋\displaystyle G' = G/B,\qquad \nu(G)=\nu(G')+\left\lfloor\frac{|B|}{2}\right\rfloor

1. 奇环识别:交替搜索树中,若同一顶点被两条不同路径到达,且形成长度为奇数的环

B=(v1,v2,…,v2k+1,v1) 为奇环\displaystyle B=(v_1,v_2,\ldots,v_{2k+1},v_1)\text{ 为奇环}

2. 收缩操作:将整个奇环压缩为一个超级顶点 \( b \),环外部边全部连到 \( b \)

G′=G/B\displaystyle G' = G/B

3. 匹配数量守恒:环内部最多匹配 \( \lfloor |B|/2 \rfloor \) 对,收缩图与原图最大匹配数相差这个值

ν(G)=ν(G′)+⌊∣B∣2⌋\displaystyle \nu(G)=\nu(G')+\left\lfloor\frac{|B|}{2}\right\rfloor

4. 展开还原:外部增广完成后,把超级顶点还原成环,并按交替规则补全内部匹配

B 展开,∣M∩B∣=⌊∣B∣2⌋\displaystyle B \text{ 展开},\quad |M\cap B|=\left\lfloor\frac{|B|}{2}\right\rfloor

Blossom算法相当于给总导演配了一个「矛盾仲裁器」:遇到三角纠结就暂时把这几个人看作一个整体单元,先解决外部大局;大局落定后再回到内部细抠。正是这个「收缩—搜索—展开」三部曲,让最大匹配从二部图扩展到任意图,理论基础由此完备。有了这套完整工具箱,我们终于可以回答最初的问题——这些算法能解决哪些真实世界的难题?

匹配应用场景

学完了四种「组队策略」,总导演身份直接切换成各行各业的「资源调度官」。最典型的场景是指派问题:有 \( n \) 个任务和 \( n \) 个人,第 \( i \) 个人做第 \( j \) 个任务需花费 \( c_{ij} \),要让总成本最小。把任务和人分别看作二部图两侧顶点,成本看作边权,就跑一趟KM算法——这正是很多排班软件、物流配送系统的内核。

调度问题同样天然是匹配模型:云计算要把GPU设备分配给计算任务,直播平台要把转码任务调度到空闲服务器,本质都是在「任务—资源」二部图上求最大匹配或最优匹配。竞赛和算法题中也常见它的变体,比如棋盘覆盖问题:用「多米诺骨牌」覆盖棋盘上可用的格子,每块骨牌占相邻两格,求最多覆盖多少——把每个可用格子看成一个顶点,相邻关系看成边,最大匹配直接给出答案。

min⁡∑i=1n∑j=1ncijxij,s.t. ∑i=1nxij=1, ∑j=1nxij=1, xij∈{0,1}\displaystyle \min \sum_{i=1}^{n}\sum_{j=1}^{n} c_{ij}x_{ij},\qquad \text{s.t. } \sum_{i=1}^{n}x_{ij}=1,\ \sum_{j=1}^{n}x_{ij}=1,\ x_{ij}\in\{0,1\}

1. 决策变量:\( x_{ij}=1 \) 表示把任务 \( j \) 指派给人员 \( i \),否则为0

xij∈{0,1}\displaystyle x_{ij}\in\{0,1\}

2. 任务约束:每个任务恰好被一个人完成,所以每列求和为1

∑i=1nxij=1\displaystyle \sum_{i=1}^{n}x_{ij}=1

3. 人员约束:每个人恰好承担一个任务,所以每行求和为1

∑j=1nxij=1\displaystyle \sum_{j=1}^{n}x_{ij}=1

4. 目标函数:所有指派的总花费最小化

min⁡∑i,jcijxij\displaystyle \min \sum_{i,j}c_{ij}x_{ij}

至此,从「如何定义合格组队」到「如何找最多队伍」,再到「如何让收益最大」和「如何处理三角恋死循环」,我们用团建组队这条主线把图匹配的整个知识版图走了一遍。这些算法并非纸上谈兵——它们正在无数调度系统中默默运行,帮人类在纷繁复杂的资源约束里寻找那个最优解。

AI 应用场景

云端GPU任务调度

阶段:模型推理与训练的资源调度层

解决的问题:AI平台每天要处理成千上万个推理请求,每个请求可被多个异构GPU执行但延迟不同。传统FIFO排队导致高延迟任务积压,GPU利用率也低。将「推理任务—GPU实例」建模为二部图,用匈牙利算法求最大匹配——优先把更多任务安排进GPU;若还要考虑SLA权重和能耗,则升级为带权最优匹配(KM算法),在有限算力下让整体服务质量最大化。

具体案例:某AI视频平台需要把转码任务分配到空闲GPU卡。每张卡同时只能跑一个任务,且不同卡执行同一任务耗时不同。平台把每时段的任务与GPU建图,边权为预估完成时间,跑KM算法求最优指派,使整批任务的加权完成时间降低约32%。

外卖平台的骑手订单指派

阶段:即时配送系统的订单分配引擎

解决的问题:午高峰上百个外卖订单同时到达,骑手运力有限,每个骑手一次只能送一单,且配送距离不同导致成本不同。传统「就近分配」只顾局部最优,容易让部分骑手空跑、订单超时。把订单与骑手建模为二部图,边权 = 预计配送时长 × 超时风险系数,用KM算法求总成本最小的完备指派,同时用匈牙利算法的增广路径思想快速应对动态入单——新订单到来时不必全量重算,只需沿着增广路径做局部调整。

具体案例:美团类配送调度系统在高峰期将订单—骑手匹配建模为最优匹配问题,结合实时路况计算边权,每5秒滚动求解一次,使超时率下降18%,骑手空驶里程减少12%。

大模型训练下的数据并行切分

阶段:分布式训练中的数据与设备规划

解决的问题:大模型分布式训练需要把不同数据分片分配给多张GPU,且通信开销因设备拓扑不同而异。通过二部图匹配(数据分片—设备节点),边权为通信延迟,用KM算法求解「通信最优」的分配方案;当设备数量不足时,用最大匹配先判断能否覆盖全部数据分片,再配合Blossom算法处理非二部约束的特殊拓扑结构。

具体案例:某AI实验室训练千亿参数模型,64张GPU组成环形拓扑。通过最优匹配切分数据与流水线阶段,通信瓶颈降低25%,训练吞吐提升近两成。

Python 演示

python42 行
def dfs(u, adj, match_r, seen):    for v in adj[u]:        if seen[v]:            continue        seen[v] = True        if match_r[v] == -1 or dfs(match_r[v], adj, match_r, seen):            match_r[v] = u            return True    return False def max_matching(n_left, n_right, edges):    adj = [[] for _ in range(n_left)]    for u, v in edges:        adj[u].append(v)    match_r = [-1] * n_right    cnt = 0    for u in range(n_left):        seen = [False] * n_right        if dfs(u, adj, match_r, seen):            cnt += 1    return cnt, match_r def perfect_matching_exists(n_left, n_right, cnt):    if n_left != n_right:        return False    return cnt == n_left if __name__ == "__main__":    # 二部图: 左侧3个任务, 右侧3台机器    # 边表示任务u可以被机器v执行    edges = [        (0, 0), (0, 1),        (1, 1), (1, 2),        (2, 1), (2, 2),    ]    n = 3    cnt, match_r = max_matching(n, n, edges)    print("maximum matching size:", cnt)    for r, u in enumerate(match_r):        if u != -1:            print("task %d -> machine %d" % (u, r))    print("perfect matching exists:", perfect_matching_exists(n, n, cnt))
目的:实现匈牙利算法求二部图最大匹配,并以「3任务×3机器」为例演示递归腾位过程,最后判断是否存在完美匹配。
  1. def dfs(u, adj, match_r, seen):递归搜索增广路径,u 是当前尝试匹配的左顶点,adj 是每个左顶点的可连右顶点列表
  2. if match_r[v] == -1 or dfs(match_r[v], adj, match_r, seen):核心「让位」逻辑:若右顶点 v 空闲则直接占用;否则递归地让 v 当前的搭档另寻他路
  3. match_r[v] = u腾位成功后,把右顶点 v 匹配给 u,匹配关系更新
  4. for u in range(n_left):依次为每个左顶点寻找增广路径,每成功一次匹配数加1
  5. seen = [False] * n_right每轮新搜索都重置访问标记,防止递归在同一轮内绕圈
  6. cnt == n_left若匹配数等于左顶点数,说明所有任务都被分配,构成完美匹配

常见误区

误区贪心算法随便挑边,直到没法再添加任何边,得到的匹配边数一定最多。既然「已经塞不下更多队伍了」,那不就是最大匹配吗?

正解极大匹配只是「局部最优」——你无法再直接添加一条边;但最大匹配是「全局最优」——所有匹配方案中边数最多。就好比团建时ABCD四人两两组队,贪心先让A和B一组、C和D一组,虽然是2队;但换个分法A和C、B和D还是2队;可如果贪心让A和B绑死,而C、D、E三人其实能组成更多队的三角关系,贪心就会漏掉最优。最大匹配必须借助增广路径不断调整,不是简单塞边能解决的。

为何常见:贪心的直觉太强——「放不下更多了」听起来就像最优。人们容易忽略增广路径带来的「换人」可能性,而正是这种连锁调整才能逼近全局最优。

误区匈牙利算法是求最大匹配的通用算法,不管图是不是二部图都能用,遇到奇环无非是搜索路径绕一点。

正解匈牙利算法只适用于二部图。它依赖「左部—右部」的交替结构,搜索才不会重访顶点;一旦遇到奇环(三角形),交替路径会从两个方向探到同一顶点,DFS腾位会无限循环或得出错误结果。处理一般图必须用Edmonds的Blossom算法——把奇环收缩成花苞再搜索。就像排班时三个人互为搭档死锁,你得先把这三人圈成「一个小组」处理,而不是让算法在三人间空转。

为何常见:教材和博客通常只讲二部图场景,很多初学者根本没接触过非二部图的反例,误以为「图」就是「二部图」。

误区只要一条路径的两端是未匹配点,中间随便走几条边,它就叫增广路径,就能让匹配数增加。

正解增广路径有严格结构:路径上的边必须严格「非匹配—匹配—非匹配—匹配」交替,且两端是未匹配顶点。只有在这种交替结构下做对称差,匹配边数才会恰好+1;如果路径上有连续两条边都属于匹配或都不属于匹配,交换后会出现顶点冲突或匹配数不增。好比换人链必须严格按「当前搭档—潜在新搭档—当前搭档」交替才能推进,中间断了一环就串不起来。

为何常见:把「增广」直观理解为「加点边」,忽略了交替性是保证「不冲突且数量+1」的关键,这是最容易被忽视的结构约束。

误区把KM算法代码拿过来,对任意二部图、任意边权矩阵都能直接运行,得到的就一定是最大权匹配。

正解经典KM算法要求图是完备二部图(左右顶点数相同且任意两点间有边),因为它的正确性依赖「可行顶标总和 = 最优匹配权值」的对偶关系,而这一关系在非完备图上不成立。处理稀疏图,惯例是给缺失边补上权值为0(或负无穷)的虚拟边,再保证左右顶点数对齐。如果不补边,算法可能误判「找不到完备匹配」。就像相亲节目必须让每位嘉宾都有心动名单,名单缺人就得空位补「零分」候选,否则配对流程无法完整进行。

为何常见:很多教程直接给 w[i][j] 矩阵,没解释矩阵本身的完备性要求;实战中直接拿稀疏图套代码,结果自然出错。

误区二部图左部有4个点右部有2个点,那最大匹配一定能把右部2个点全部匹配上;甚至左部4个右部4个时,最大匹配一定是完美匹配。

正解最大匹配的大小受边结构限制,不是顶点数量说了算。比如右部某个顶点没有任何边相连,它永远无法被匹配;左部4点右部4点的图也可能最大匹配只有2。判断能否全覆盖,需要Hall定理或者直接计算最大匹配数并与较小部顶点数比较。组队的根本约束是「有人愿意跟谁组队」,没有合作意愿的边,人数再多也白搭。

为何常见:大脑常把「顶点数」当成本质约束,忽略了「边是否存在」这个前提。匹配问题中,边才是决定上限的真正瓶颈。

面试题

Q1. 以下关于图中匹配的说法,正确的是?

单选题 · easy

  • A.匹配中的任意两条边可以有公共端点
  • B.匹配是任意边组成的集合
  • C.匹配中任意两条边没有公共端点← 正确答案
  • D.匹配必须包含图中的所有顶点

答案:C。匹配的核心定义是「边集中任意两条边不相交」,即无公共端点,对应C。A是反面定义;B漏掉了「互不相交」的约束;D说的是完美匹配,普通匹配不需要覆盖所有顶点。好比团建组队时每个人只能参加一队,而不是某人可以同时出现在两支队伍里。

Q2. 一个图有10个顶点,其最大匹配的边数至多为多少?

单选题 · easy

  • A.3
  • B.4
  • C.5← 正确答案
  • D.10

答案:C。每条匹配边消耗2个不同顶点,所以匹配边数上限是顶点数的一半,即 ⌊10/2⌋=5。这是匹配的边数上界公式 \( |M|\le\lfloor n/2\rfloor \)。好比10个人组双人队,最多只能组5队,不可能组出6队。

Q3. 匈牙利算法不能直接求解以下哪种图的最大匹配?

单选题 · mid

  • A.完全二部图
  • B.稀疏二部图
  • C.含奇环的一般图← 正确答案
  • D.树形二部图

答案:C。匈牙利算法适用于二部图,包括完全二部图、稀疏二部图和树形二部图。但含奇环的一般图会让交替搜索树重复访问同一顶点、陷入死循环,必须改用Blossom算法。三角恋式的三个人互相指向对方,就是奇环对算法的致命干扰。

Q4. 关于增广路径,以下描述正确的是?

单选题 · mid

  • A.路径上所有边都属于当前匹配
  • B.路径上所有边都不属于当前匹配
  • C.起点和终点都是未匹配顶点,且匹配边与非匹配边交替← 正确答案
  • D.路径任意,只要边数大于匹配数即可

答案:C。增广路径要求边严格交替属于/不属于当前匹配,且两端点是未匹配顶点。C完整描述了这两个必要条件。A只有匹配边无法「增广」;B相当于一条普通非匹配路径;D忽略了交替结构和端点条件。

Q5. 对于一个当前匹配 M,若找到一条增广路径 P,下列说法正确的是?

多选题 · mid

  • A.沿 P 做对称差后,匹配数增加 1← 正确答案
  • B.对称差运算为 \( M\oplus P = (M\setminus P)\cup(P\setminus M) \)← 正确答案
  • C.沿 P 交换后,P 上原来的匹配边变为非匹配边← 正确答案
  • D.沿 P 交换后,所有顶点都会被匹配

答案:ABC。增广路径上非匹配边比匹配边多一条,对称差交换后匹配数+1(A对);对称差定义正是B;交换后路径上原匹配边变为非匹配边、原非匹配边变为匹配边(C对)。D错误——交换只保证匹配数+1,不保证达到完美匹配,除非原本就是最后一个未匹配顶点。

Q6. KM算法的可行顶标需要满足什么条件?

单选题 · mid

  • A.\( l(x)+l(y)=w(x,y) \) 对所有边成立
  • B.\( l(x)+l(y)\ge w(x,y) \) 对所有边成立← 正确答案
  • C.\( l(x)+l(y)\le w(x,y) \) 对所有边成立
  • D.\( l(x)\cdot l(y)=w(x,y) \) 对所有边成立

答案:B。可行顶标要求任意边两端顶标之和不小于边权,即 \( l(x)+l(y)\ge w(x,y) \)。「等于」只对相等子图中的边成立,而非所有边;「小于」会让顶标总和低于真实匹配权值,破坏最优性证明;D完全不符合定义。标价牌只能把组合价值标得「不低于」真实收益,才能锁定天花板。

Q7. 关于最大匹配与完美匹配的关系,下列说法正确的有?

多选题 · mid

  • A.完美匹配一定是最大匹配← 正确答案
  • B.最大匹配不一定是完美匹配← 正确答案
  • C.若图有偶数个顶点,则一定存在完美匹配
  • D.完美匹配要求匹配边覆盖所有顶点← 正确答案

答案:ABD。完美匹配覆盖所有顶点,边数达到 ⌊n/2⌋ 的上界,因此必然是最大匹配(A对);最大匹配可能达不到全覆盖,所以不一定是完美匹配(B对);完美匹配的定义就是覆盖所有顶点(D对)。C显然错误——偶数顶点只是必要条件,图结构不满足时照样没有完美匹配。

Q8. 贪心算法得到的极大匹配,与最大匹配的关系是?

单选题 · easy

  • A.两者一定相等
  • B.极大匹配的边数一定不少于最大匹配
  • C.极大匹配的边数可能少于最大匹配← 正确答案
  • D.两者一定无关

答案:C。极大匹配只是「无法再直接加边」的局部最优,而最大匹配是全局最优;极大匹配的边数可能少于最大匹配。比如贪心先占用了关键顶点,可能导致后续无法增广。增广路径的存在正是为了突破局部最优,这是从极大走向最大的关键。

Q9. 在Blossom算法中,遇到奇环后需要进行哪些操作步骤?

多选题 · hard

  • A.将奇环收缩为一个超级顶点← 正确答案
  • B.在收缩后的图上继续寻找增广路径← 正确答案
  • C.找到增广路径后,展开超级顶点还原内部匹配← 正确答案
  • D.直接将奇环中的所有边加入匹配

答案:ABC。Blossom算法的核心三步:收缩奇环为花苞(A)、在收缩图上继续搜索增广路径(B)、外部找到路径后展开花苞并补全内部匹配(C)。D错误——把奇环所有边都加入匹配会违反「无公共端点」的定义,奇环内部最多只能匹配 ⌊|B|/2⌋ 对。

Q10. 需要把 n 个任务分配给 n 个人员使总成本最小,且每个任务只能分配给一个人。最适合的算法是?

单选题 · hard

  • A.匈牙利算法求最大匹配
  • B.KM算法求最优匹配← 正确答案
  • C.Blossom算法求最大匹配
  • D.贪心按最小成本逐个分配

答案:B。这是典型带权完备指派问题,KM算法的可行顶标与相等子图机制正是为此设计,能在 \( O(n^3) \) 时间内保证总成本最小(B对)。匈牙利算法只求匹配数最多、不计权值(A错);Blossom处理非二部图最大匹配(C错);贪心逐个分配是局部最优,无法保证全局最小(D错)。