Loading

【笔记】二分图

二分图:可以把所有点分为两个点集,相同点集里的点之间没有边的无向图

当且仅当一个无向图中有奇环存在时,这个图不是二分图。

第一部分:二分图判定 - 染色法

我们可以把图中的点染成两种颜色,白色是一个点集,黑色是另一个点集。

染色的规则:因为相同点集里的点之间没有边,所以每个节点的颜色必须与父节点不同。

实现方法:从任意一个节点开始遍历,模拟染色的过程。当遇到已经遍历过的结点时,如果这个结点又要被染成另一种颜色,那么这个图就不是二分图。使用 DFSBFS 实现。

连通块:如果图不连通,那么当所有连通块都是二分图的时候,整个图也是一张二分图。因此在遍历的过程中要对所有连通块分别染色。

bool dfs(int root,int col){
	vis[root]=1;
	c[root]=col;
	for(int i=h[root];i;i=e[i].nxt){
		int v=e[i].to;
		if(vis[v]){
			if(c[root]!=c[v]) continue;
			else return 0;
		}
		if(!dfs(v,col^1)) return 0;
	}
	return 1;
}
for(int i=1;i<=n;i++){
	if(!vis[i]){
		if(!dfs(i,0)){
			cout<<"NO";
			return 0;
		}
	} 
}
cout<<"YES";

时间复杂度:\(O(n+m)\)

另:并查集判断二分图

把每一个点拆成两个点,对于一条边 \((u,v)\),拆分为 \((u,v+n)\)\((u+n,v)\)

判断是否出现 \((u,u+n)\)\((v,v+n)\) 即可。

bool check(){
	for(int i=1;i<=m;i++){
		Merge(e[i].u+n,e[i].v);
		Merge(e[i].u,e[i].v+n);
		if(Find(e[i].u)==Find(e[i].u+n)||Find(e[i].v)==Find(e[i].v+n)) return 0;
	}
	return 1;
}

第二部分:二分图最大匹配 - 匈牙利算法

记二分图 \(G\langle V_1,V_2,E\rangle\)\(V_1,V_2\) 为两个点集,\(E\) 为边集。

在二分图中选择若干条边组成一个边集合,使得边集中的边连接的点两两没有公共点

最大匹配:边数量最多的匹配。

匈牙利算法:求二分图最大匹配的算法。

算法思路:考虑贪心求解。遍历集合 \(V_1\) 中的每个点 \(u\),寻找 \(u\) 的邻居结点(与 \(u\) 相连),如果 \(v\) 还没有被匹配,那么将 \(v\)\(u\) 配对;如果 \(v\) 匹配过了,那么就去寻找与 \(v\) 配对的结点 \(k\) 的其他邻居结点,如果 \(k\) 能按照同样的方式找到新的匹配,那么就把 \(k\) 与新匹配配对,把 \(v\)\(u\) 配对。如果 \(k\) 无法找到新匹配,那么 \(u\) 也就匹配失败。

实现方式:维护一个数组 \(p\),记录 \(V_2\) 中的点与 \(V_1\) 中的点的配对情况,以及一个标记数组 \(vis\) 记录结点是否被遍历过。对每个结点都进行上述操作,每次清空 \(vis\),即可求出最大匹配。

//p:匹配的节点。vis:是否遍历过。
bool dfs(int root){
	if(vis[root]++) return 0;
	for(int i=h[root];i;i=e[i].nxt){
		int v=e[i].to;
		if(!p[v]||dfs(p[v])){
			p[v]=root;
			return 1;
		}
	}
	return 0;
}
for(int i=1;i<=n;i++){
	if(dfs(i)) ans++;
	for(int j=1;j<=n+m;j++) vis[j]=0;//每次清空vis
}

时间复杂度 \(O(n(n+m))\)

衍生问题:二分图最小点覆盖、二分图最大独立集、最小路径覆盖

最小点覆盖:选一些点,使得每条边两端至少有一个被选中。二分图中,最小点覆盖=最大匹配(一般图中为 NP Hard 问题)。

最大独立集:选一些点,使得每条边两端至多有一个被选中。也就是一个点集,点集中的各点没有关系。最大独立集和最小点覆盖互补,任何一个最小点覆盖,它的补集一定是最大独立集。二分图中,最大独立集=总点数-最大匹配。(一般图中为 NP Hard 问题)。

最小路径覆盖:选择一些路径,覆盖所有点集,且各路径点集之间不允许有交集,要求路径数最少。有向无环图可进行拆点(每个点 \(u\) 拆成两个点 \(ul\) 出点和 \(ur\) 入点,边 \((u,v)\) 变为 \((ul,vr)\),因为原图是有向无环图,所以拆点后为二分图)。有向无环图的最小路径覆盖,就是原图结点数-拆点后二分图最大匹配数。

第三部分:Hall 定理

二分图完美匹配:设有二分图 \(G\langle V_1,V_2,E\rangle\),边集 \(M\) 为其中的最大匹配,且 \(|M|=|V_1|\),则 \(M\)\(V_1\)\(V_2\) 的完美匹配。

设有二分图 \(G\langle V_1,V_2,E\rangle\)\(|V_1|\le|V_2|\),如果 \(G\) 中存在 \(V_1\)\(V_2\) 的完美匹配,当且仅当对于任意的点集 \(S \subset V_1\),均有 \(|S| \le |N(S)|\),其中 \(N(S)\)\(S\) 的邻居集合,即与 \(S\) 点集有边相连的所有点的集合(全部在 \(V_2\) 集合里)。

posted @ 2025-12-12 22:50  Seqfrel  阅读(0)  评论(0)    收藏  举报