二分图网络流选讲

前言

完稿时间:2024.6.30

二分图网络流选讲

二分图

定义

  • 无向图
  • 节点可两集合
  • 每个集合中的节点互不连边

性质

  • 将两个集合中的点分别染成黑色和白色,可以发现二分图中的每一条边都一定是连接一个黑色点和一个白色点(废话)
  • 图中没有长度为奇数的环

证明性质2:因为每一条边都是从一个集合走到另一个集合,只有走偶数次才可能回到同一个集合。

二分图匹配

  • 匹配:有一个边集E,且E中的边都没有公共端点
  • 最大匹配:边最多的匹配
  • 完备匹配:所有点都有匹配点

增广路

增广路是一条非匹配边和匹配边交替的路径。增广路从非匹配边开始,非匹配边结束。

  • 增广路中边数为奇数
  • 将匹配边与非匹配边反转,则匹配边数+1

增广路定理:一个匹配是最大匹配当且仅当没有增广路

证明:如果存在就可以反转,匹配数可以+1与最大匹配矛盾

二分图最大匹配匈牙利算法

简述:不断在二分图里找增广路,反转匹配状态,直到找不出增广路。

算法流程

  • 枚举每个左部点,为它在右部找一个匹配点
  • 如果找到了还没被匹配过的点,那么匹配成功
  • 如果找到了已经被匹配过的点x,那么尝试为x匹配的点换一个匹配

代码

#define FL(i, a, b) for(int i = a; i <= b; i++)
int n, m, t, mat[N], ans;//mat[i]表示右边编号i匹配的左边节点
vector < int > g[N];
bool find(int u){
	for(int i = 0; i < g[u].size(); i++){
		int v = g[u][i];
		if(vis[v])continue; vis[v] = true;//去重
		if(!mat[v] or find(mat[v])){
			mat[v] = u;
			return true;
		}
	}
	return false;
}
int main(){
    ...
	FL(i, 1, n){//枚举左边的点
		memset(vis, false, sizeof vis);
		if(find(i))ans++;//匹配
	}
    cout << ans;
}

例题 P2071 座位安排

思路

人放左边,座位在右边,建模跑二分图最大匹配板子

代码

int main(){
	cin >> n; n *= 2;
    for(int i = 1, u, v; i <= n; ++i){
        cin >> u >> v;
        g[i].push_back(2 * u - 1);
        g[i].push_back(2 * u);
        g[i].push_back(2 * v - 1);
        g[i].push_back(2 * v);
    }
}

网络流

详见 网络流专题

posted @   Lyrella  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示