二分图总结
为什么只写二分图而不写其他图论内容呢?
因为刚学。
二分图
定义
二分图是一个没有长度为奇数的环的无向图。
二分图一定可以被染色成
常见的判断图是否为二分图的方法可以染色,如下:
bool lab;
void dfs(int now,int sta,int minn){
col[now]=sta;
for(int i=0;i<e[now].size();i++){
if(v[now][i]<minn)continue;
int y=e[now][i];
if(!col[y]){
dfs(y,3-sta,minn);
}
else{
if(col[y]==col[now]){
lab=1;
}
}
}
}
二分图的匹配
二分图可以画成左一部分,右一部分的图示:
二分图的匹配就是选择一些边,使其任意两条边之间没有共同顶点。
二分图的最大匹配就是选择的边最多的方法。
二分图的匹配边就是选出来的边
二分图的匹配点是指所有匹配边的顶点组成的集合。
如何求最大匹配
常用:增广路算法。
我们对与每一个在左侧的点,递归寻找有无还未匹配上的右侧节点。
有的话直接匹配,用 match
数组记录右侧节点的匹配情况,并返回成功。
之后对于每一个相连的右侧节点,查看其与之对应的 match
是否能在找到一个匹配的,递归,如果可以,返回成功。
如果每条出边都无法匹配,返回失败。
我们可以开一个 vis
数组表示右侧节点的遍历情况。
在枚举左侧点时清空,原因:
我们每次枚举左侧点时,每次情况都不同,而递归内,每次情况都是相同的。
代码:
int match[N];
bool vis[N];
bool dfs(int now){
for(auto y:e[now]){
if(vis[y])continue;
vis[y]=1;
if(!match[y]||dfs(match[y])){
match[y]=now;
return 1;
}
}
return 0;
}
In main:
for(int i=1;i<=n;i++){
memset(vis,0,sizeof vis);
if(!dfs(i)) ans++;
}
二分图最小点覆盖
定义:最小点覆盖是指选中最少的点,使每条边的端点至少有一个被选中。
先说结论:二分图最小点覆盖等于其最大匹配数。
证明:
显然,其最小点覆盖的点数要大于等于其最大匹配数。
之后我们尝试构造一种等于其最大匹配数的解法。
我们先跑一遍二分图匹配。
然后对于每一个没匹配上的左部节点都再递归一遍标记途径节点。
这样做有三个性质:
- 左侧的未匹配点一定有标记;
- 右侧的未匹配点一定没标记;
- 匹配边所连接的两点一定同有或无标签。
我们选择左边未标记的节点,再选右侧已标记的节点,先证明这样选是覆盖的:
我们分类讨论:
- 这条边是匹配边,由第三条性质可知其一定被覆盖。
- 这条边左端点是匹配点,右端点不是匹配点:因为右端点没标记,所以左端点一定也没标记,否则其就不是一个最大匹配。
- 这条边左端点不是,右端点是:因为左端点有标记,所以右端点一定也有标记。
- 这条边左右两边都不是匹配点:不可能有这样的边。
之后再证明其大小为最大匹配:
对于每条匹配边,其两顶点只会有一个被选。
对于每个非匹配点,其都不会被选。
二分图最大独立集
定义:独立集是指无向图中选取一些点,任意两点之间没有连边的一个。
结论:二分图最大独立集等于节点数减去最大匹配数。
我们知道二分图最大独立集可以看作选取一些点删掉,并且删掉与之相连的边,使之后的图没有边。
而这个条件可以看成选出最少的点,使之覆盖每条边。
这就是 二分图最小点覆盖,于是结论得证。
有向图最小路径覆盖
我们先讨论不可重复经过同一点的情况。
我们