二分图 学习笔记
怎么联合省选前啥都不会,但还是要尽力。
不放歌了,更加清爽一些。
定义:
-
一个无向图,满足他的所有点可以被划分成两个集合 ,相同集合内的点没有连边。这是从点的角度。
-
一个无向图,每一条边所对应的两个点属于不同的集合 。这是从边的角度,个人感觉这个角度好理解。
这两个点集称为互补点集,这个图就是二分图,可以写作 ,如果 所有节点和 邻接,那么这就是完全二分图,记 ,完全二分图可以写成 ,其中 就是菊花图。
注意, 的划分不一定唯一。
同时,以下定义都是二分图:
- 无向图 中没有奇环。(偶环可以二染色,图可以看成偶环缩点+DAG,现对DAG染色,然后对偶环染色即可。)
- 无向图 可以二染色。(可以二染色就代表了每一条边对应的两个点属于不同集合。)
容易发现,树是二分图。
二分图染色
首先你要判断这个图是一个二分图。
染色的目的是要方便表示相对的关系,更加直观一些。
从边的角度考虑,很显然,如果确定了当前点的颜色,那么与他相连的点的颜色就能确定了。
那你不断染色以后,如果发现冲突(相邻点颜色相同),那就必然无解。
二分图匹配
匹配:定义如果一个无向图 中找到一个边集 ,使得 中任意两条边不邻接(没有公共点),那么 就是 的一个 匹配。
如果 是所有方案中最大的,那说明 是二分图的最大匹配。
如果 中所有的点都和 关联,那么这个匹配 就是完美匹配,因为如果此时再加边的话就会有两条边邻接了,所以 完美匹配 一定是 最大匹配。
有结论:若 有完美匹配,说明 。因为每次新加边都有新的两个点。
一种理解方式,你往 加边的过程,每次就宣告了不能选取某两个点的所有边了。
如果 ,假定, 是一个匹配满足 的话, 就是一个 完备匹配,完备匹配 也是 最大匹配,因为你每连一条边就用掉了 的一个点,最多就是 个了,如果你从 开始不优。
霍尔定理: 有完备匹配的充要条件是(可以互推):对于任意正整数 ,满足 中任意 个点和 至少 个点相连。
我所能知道的只有两个:
- 如果不具备这样的条件的话,那么 多个点可以连向 一个点,这时候 大小就一定不符合,就不是完备匹配。
实现(寻找二分图最大匹配):
匈牙利算法。
因为是要求找到的边尽可能多,那么实际上就是能覆盖到的点尽可能多。尽量从边的角度考虑,再推到点。
二分图最大匹配对点的最大限制就是一个点仅可以对应一个点,同时保证数量最大。
定义一个数组 表示和 匹配的点,初始值是 。
流程:
- 在 中找到一个未尝试的点 。
- 找到一条和 关联但是没尝试过的边 。
- 如果 未被匹配,那么 和 匹配,跳到 。
- 如果 匹配过了,不妨让 重新进行一个匹配(回到 ),如果能匹配成功,那么 和 匹配,到 ,否则到 。
- 如果还有没有尝试的边,接着尝试(跳到 ),否则到 。
- 如果还有没有尝试的点,到 ,否则结束。
正确性保证是霍尔定理。
尝试了 个点,然后最坏情况下每条边都试一次,时间是 的。
bool color(int u){
vis[u]=1;
for(int i=0;i<g[u].size();i++){
int v=g[u][i];
if(mat[v]==-1||(vis[mat[v]]==false&&color(mat[v]))){// 防止走环回来
mat[v]=u,mat[u]=v;
return 1;
}
}
return 0;
}
void Match(){
memset(mat,-1,sizeof(mat));
int ans=0;
for(int i=1;i<=n;i++){
if(mat[i]==-1){
memset(vis,0,sizeof(vis));
if(color(i)) ans++;
}
}
cout<<ans<<endl;
}
二分图染色板,但是自己一开始还看错结论,抽象。
我们不妨把任意一点赋值为 ,很显然,和他周围的点就要赋值成 ,这样一直染色下去即可。如果发现冲突就是无解。
因为你染色这个东西是相对的,所以你可以认为你在所有 的位置放了河蟹,也可以认为你在所有 的位置放了河蟹,两种情况取最小即可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现