【学习笔记】二分图
二分图
图上的点可以完美的被分成两部分,使得每一个部分的点中互相没有连边
或者说:可以黑白染色、没有奇环
判定
直接 染色
inline void dfs(int x){
for(int i=head[x];i;i=e[i].nxt){
int t=e[i].to;
if(col[t]==-1) col[t]=1-col[x],dfs(t);
}
return ;
}
这里的 就是表示每个点所属于的点集标号
我第一次写的是按照 这样走的,还可以有 (就是在 计算的时候拿 减呗)
最大匹配
匹配:二分图的一个边集,使得边集中的所有边没有公共端点
最大匹配:边集中 最大的一个
匹配边:顾名思义,在匹配的边集中的边
增广路(交错路):一个从连接左部非匹配点和右部非匹配点的路径
使得匹配边和非匹配边交替出现,长度应为奇数
正是增广路的这个定义,使得我们可以在找到一条增广路的时候把路径上的所有的边取反,然后边集大小会
求解主要是匈牙利算法
就是每次dfs找增广路,如果找到了答案加
inline bool dfs(int x){
for(int i=head[x];i;i=e[i].nxt){
int t=e[i].to; if(vis[t]) continue;
vis[t]=1;
if(to[t]==-1||dfs(to[t])) return to[t]=x,1;
}
return 0;
}
最小点覆盖
在二分图中的一个点集,使得图中所有边都存在至少一个端点属于这个点集
定理:
二分图最小点覆盖集的大小 二分图最大匹配集的大小
先说构造最小点覆盖的方法:
-
求出最大匹配。
-
从右部每个未匹配点出发寻找增广路(一定失败,要不然就不是最大匹配了),标记访问过的节点。
-
取左部标记点、右部未标记点,构成一组最小覆盖。
证明
经过上述构造方法后
右部未匹配点一定是标记点——因为它们是出发点
左部未匹配点一定是未标记点——如果被标记则找到了增广路(两边都是未匹配点诶)
一对匹配点都被标记或者都未标记——因为左部匹配点只能通过右部到达
取左部标记点、右部未标记点,恰好使得每对匹配点被取走一个
所以数量值相等
匹配边一定被覆盖——每对匹配点取走一个
不存在连接两个未匹配点的边——否则出现仅包含1条边的增广路
连接左部匹配点和右部未匹配点的边——后者是出发点,前者一定被标记
连接左部未匹配点和右部匹配点的边——后者未被标记,否则存在增广路
所以所有的边都被覆盖了,大功告成
最大独立集
定义:任意两点在图中都没有边相连的点集称为图的独立集。
定理:二分图最大独立集 图的点数 二分图最大匹配
证明:选出最多的点构成独立集
在图中去掉最少的点,使剩下的点之间没有边。
用最少的点覆盖所有的边,去掉的是最小覆盖。
例题:骑士放置
给定一个 的矩形和几个禁止放置点,求最多可以放几个骑士
首先看出来是求最大独立集不难吧
建图就是对当前点和可以被攻击的点建图就行
同时我们发现骑士所在的位置和可以攻击到的位置的 横纵坐标之和 是不一样的
这样就可以省略 染色的过程了,直接建图的时候看一下奇偶性就可以了
最小路径覆盖问题
最小路径覆盖:用尽量少的不相交简单路径覆盖有向无环图的所有顶点。
做法:把每个点拆成左边右边两个,对于每条边,链接
跑最大匹配,最小路径覆盖数 = 原有向图节点数 – 新二分图最大匹配数
证明:
按照定义,我们选取的路径上的点都是入度、出度为的
除了起点没有入度,终点没有出度
而拆点就是因为匹配中每个点的连接的边不多于 条
路径上的边对应匹配边,有向图中的出点对应左部点
所以最小路径覆盖 最小未被匹配的点 最大匹配
例题如下
似乎是模板题
首先要发现这个题的两个相交的路径: 和路径
这里如果我们添加一条边
那么问题又转化成了最小点覆盖( 和 )
这里搞一个 传递闭包搞连通性然后最大匹配就好了
例题
- 有障碍点建图 USACO Muddy Fields
(贪心一发,如果重叠少的做法肯定优)
我们发现这个木板只有横竖两种摆放方式,而且如果都放在这里的话就重叠了
所以我们让每行每列为点,每个行列的交点为边建图,然后是个最小点覆盖
建图:如果遇到障碍点标号就加一,障碍点在这里的定义是好地
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
if(g[i][j]=='*') ++c1;
while(g[i][j]=='*') id1[i][j++]=c1;
}
}
for(int j=1;j<=m;++j){
for(int i=1;i<=n;++i){
if(g[i][j]=='*') ++c2;
while(g[i][j]=='*') id2[i++][j]=c2;
}
}
- Tyvj1935 导弹防御塔
首先我们这个最值并不好做,那么转二分答案
二分时间 看 是不是可行
在 函数里面做二分图完备匹配
预处理每一座塔和每个入侵者的距离
塔和入侵者是可以分列左右的,所以这玩意是个二分图
拆点:若某座塔在 秒内可以发射 次导弹,就把这座塔拆成 个点。
建边的条件:
导弹 在 秒时发射,飞到入侵者 需 秒,若 ,就连边
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律