二分图学习笔记
如果一张无向图的
二分图的判定
定理:一张图是二分图,当且仅当图中不存在奇环。(证明略,感性理解一下qwq)
时间复杂度为
bool dfs(int x,int mid,int col)//若是二分图返回true
{
c[x]=col;
for(int i=lk[x];i;i=nxt[i])
{
int y=to[i];
if(val[i]<=mid)continue;
if(!c[y]&&!dfs(y,mid,3-col))return false;
else if(c[y]==c[x])
{
return false;
}
}
return true;
}
例题:关押罪犯
有
名罪犯,编号从 到 ,共有 座监狱,给出 对关系,表示把罪犯 和罪犯 安排在同一所监狱的代价为 ,求出安排使得所有代价最大值(不是求和)的最小值。
分析:最大值的最小值,可以想到二分。我们设每次二分需要对当前的
二分图最大匹配
任意两条边没有公共端点的边集成为二分图的匹配。在二分图中包含最多边的一组匹配成为二分图的最大匹配。
对于一组匹配
增广路显然具有性质:
- 长度为奇数;
- 路径上第奇数条边为非匹配边,其余为匹配边.
由于以上性质,我们显然可以把路径上所有路径取反,得到一组新的匹配,并且匹配边数加一。太好了!
进一步得到推论:二分图的一组匹配
匈牙利算法(增广路算法)
用于计算二分图的最大匹配。主要过程为:
- 设
。 - 寻找增广路
把路径上所有匹配状态取反,得到一个更大的匹配 。 - 重复第二个步骤,直到图中不存在增广路。
算法的关键在于如何寻找增广路。匈牙利算法依次尝试给每一个左部节点
本身为非匹配点。 已经与左部点 匹配,但是从 出发能够找到另一个与之匹配的点 。此时 为一条增广路。
整体复杂度为
bool dfs(int x)//若能找到增广路,返回true
{
for(int i=lk[x];i;i=nxt[i])
{
int y=to[i];
if(vis[y])continue;
vis[y]=true;
if(!match[y]||dfs(match[y]))
{
match[y]=x;return true;
}
}
return false;
}
二分图匹配的模型有两个要素:
- “ 0 要素”:节点可以分成两个内部有 0 条边的集合;
- “ 1 要素”:每个节点只能与一条匹配边相连。
例题:棋盘覆盖
给定一个
的棋盘,有 个禁止放置的位置,问最多能放多少块 的骨牌。
分析:本题中的 “1” 为每个格子只能被一块骨牌覆盖。如果把棋盘按照“黑白黑白\n白黑白黑”的方式染色,显然同色的格子之间是没有连边的。要让骨牌在不重叠的情况下尽量多放,就是求以每个格子为节点,相邻格子代表的节点之间连边的二分图的最大匹配数。
二分图最大匹配的必须边与可行边
对于完备匹配,求出最大匹配后,我们把匹配边从右向左连有向边,对于非匹配边,从左向右连边。如果一条边是匹配边而且端点不在同一个强联通分量中,则是必须边;若一条边是匹配边或者端点在同一个强联通分量中,为可行边。
例题:Sorting Slides
显然是完备匹配,只需求二分图最大匹配的必须边。
完备匹配
给定一张二分图,左右两边均为
多重匹配
给定一张包含
此问题一般有四种解决方案:
- 拆点。
- 如果只有左侧是多重匹配,可以直接让每个左侧的节点执行
次 dfs。 - 如果只有右侧是多重匹配,让右部节点可以匹配
次,超过匹配次数后,依次递归尝试当前匹配的 个左部节点,看是否能找到增广路。 - 网络流。最高效的解决方法orz。
例题:Steady Cow Assignment
有
头牛和 座房子,每头牛对这些房子有一个喜好排列,每座房子有一个最大容纳量,在房子能容纳下的情况下,问怎样安排可以使每头牛属于的房子在各自的房子喜好排列中的下标的最大值和最小值的差值 最小。(大概就是这个意思)
分析:“0”是显然的,“1”是每头牛只能属于一座房子。但是一座房子可以容纳多头牛,考虑拆点,这样依然可以保证拆点后的图依然是一一匹配。虽然
二分图带权匹配
有两种解法:费用流和KM算法。在稠密图上,KM算法的效率高于费用流,代码实现也更加简单。不过KM算法也有很大的局限性,只能满足在“带权最大匹配一定是完备匹配”的图中正确求解。
交错树
在匈牙利算法中,如果从某个左部节点出发寻找匹配失败,那么在 dfs 的过程中,所有访问过的节点以及经过的边构成一棵树,这棵树的根节点和叶子结点都是左部点,第奇数层的边是非匹配边,偶数层的边是匹配边。因此,这棵树被称作交错树。
顶标
即“顶点标记值”。二分图中,给每个左部节点一个整数值
相等子图
二分图中所有节点和满足
定理:若相等子图中存在完备匹配,则这个完备匹配就是二分图的带权最大匹配。
二分图的最小点覆盖
给定一张二分图,求出一个最小的点集
定理
二分图最小点覆盖包含的点数等于二分图最大匹配包含的边数。
二分图最小点覆盖的构造方法如下:
- 求出二分图的最大匹配;
- 从左部每个非匹配点出发,再执行一次 dfs 寻找增广路的过程,标记访问过的节点;
- 取左部未被标记的点和右部被标记过的点,就得到了二分图的最小点覆盖。
正确性证明略。
例题:Machine Schedule
给出
个任务,每个任务可以选择用机器 在模式 下完成,或者用机器 在模式 下完成,完成的顺序任意。问最少转换模式多少次可以完成所有任务。
分析:“0”依然是显然的,“1”是每个任务只能被一个机器完成,二分图最小覆盖模型还有一个“2”要素:每条边的两个端点至少选择一个。这里就是每个任务至少要选择一个机器来完成。把每个任务视作一条边,每种模式视作一个节点,求出二分图的最小覆盖就是答案。这个初始状态为
二分图最大独立集
定理:
- 无向图的最大团等于其补图的最大独立集。
- 二分图的最大独立集的大小等于点的数量减去最大匹配数。
例题:骑士放置
一个
的棋盘上,给定 个无法放置的位置,问最多能放多少个无法相互攻击的骑士。骑士可以攻击“日”字型对角线的棋子。
分析:显然两个可以攻击到的棋子在按照上一道棋盘的题的染色方式染色后会属于两个不同的颜色集合,再在这样的两个节点之间连边,求出此图的最大独立集即可。
也可以用最小覆盖来看此题。把每个格子的初始状态想成有棋子,如果几个节点的共同可以攻击的位置上是空的(对应一个选中的节点覆盖了若干条边),这几个位置就算到了(大概就是这个意思)。算出二分图的最小覆盖为
有向无环图的最小路径点覆盖
给定一张有向无环图,要求用尽量少的不相交的简单路径覆盖所有顶点,这个问题被称为有向无环图的最小路径点覆盖。
我们把原来有向图中的每条边 x<<1,y<<1|1
么),我们有定理,拆点前最小路径点覆盖包含的路径条数等于
例题:捉迷藏
题意略。
分析:此题要求有向无环图的最小路径可重复覆盖,考虑在可重复的点两边,跨过这个点连边,也就是给所有可以间接到达的点之间连边,所以先跑一遍传递闭包再按照普通的最小路径覆盖求就好了。
总结:
怎么什么都是最大匹配数最重要的是建模。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具