【学习笔记】二分图&网络流
二分图
定义
在一张图中,如果能够把全部的点分到两个集合中,保证两个集合内部没有任何边,图中的边只存在于两个集合之间,这张图就是二分图
判断(染色法)
用黑白两种颜色对图中点染色(将点加入集合),一个点是不能同时有两种颜色的,若有,此图不是二分图
根据染色法,我们发现,二分图内部是绝对不会存在奇环的,不存在奇环的图就是二分图
所以我们对图进行DFS或者BFS,发现奇环就跳出,此图不是二分图
二分图判断
bool dfs(int u,int c){
color[u]=c;
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(color[j]){
if(color[j]==c){
return false;
}
}
else if(!dfs(v,3-c)){
return false;
}
}
}
bool check(){
memset(color,0,sizeof color);
for(int i=1;i<=n;i++){
if(color[i]==0){
if(!dfs(i,1)){
return false;
}
}
}
return true;
}
二分图的匹配
给定一个二分图\(G\),\(M\)为\(G\)边集的一个子集,如果\(M\)满足当中的任意两条边都不依附于同一个顶点(没有公共端点),则称\(M\)是一个匹配
二分图的最大匹配
图中包含边数最多的匹配称为图的最大匹配
完美匹配
如果所有点都在匹配边上,称这个最大匹配是完美匹配
增广路定理\(Berge'slemma\)
交错路:始于非匹配点且由匹配边与非匹配边交错而成
增广路:是始于非匹配点且终于非匹配点的交错路,路径的长度一定为奇数5
增广路上飞匹配边比匹配边数量多以,如果将匹配边改为未匹配边,未匹配边改为匹配边,则匹配大小会增加一且依然是交错路,匹配数增加的过程,我们称之为增广
增广路(匈牙利)算法\(Augmenting\ Path\ Algorithm\)
核心思想:枚举所有未匹配点,找增广路径,在增广路上关于匹配取反,直到找不到增广路
算法思路:
1.将匹配边集\(M\)置为空
2.找一条增广路径\(P\),\(P\)上的边取反得到一个更大的匹配\(M\)
3.重复上一步直到找不到增广路径为止
算法本质:贪心
实现方法:搜索(递归)
最坏情况会每个点遍历全部边一次,时间复杂度\(O(nm)\)
匈牙利算法
bool find(int x){
for(int i=1;i<=n;i++){
if(!st[i]&&g[x][i]){
st[i]=true;
int t=match[i];
if(!t||find(t)){
match[i]=x;
return true;
}
}
}
return false;
}
int main(){
cin>>n;
int ans=0;
for(int i=1;i<=n;i++){
memset(st,0,sizeof(st));
if(find(i)){
ans++;
}
}
cout<<ans;
return 0;
}
棋盘覆盖
给定⼀个\(N\)行\(M\)列的棋盘,已知某些格⼦禁⽌放置。
求最多能往棋盘上放多少块的⻓度为\(2\)宽度为 \(1\)的骨牌,骨牌的边界与格线重合(骨牌占⽤两个格子),并且任意两张骨牌都不重叠。
将棋盘黑白染色,相邻的各自染成不同的颜色,染色后格子分为黑白两类,对应二分图模型中的\(X\)和\(Y\)集合