二分图

「理论上到现在应该已经学习完了所有 NOIP 考纲内的知识点,如果还有不会的赶紧学习。」

突然发现自己从来没有学过二分图。想起来去年本来想学,但是看了一下好像没怎么考,学别的去了。

二分图基础

定义

对于一张图,如果其点集可以划分为两个部分,且图上的每一条边的两个端点都不在同一个部分中,则称这个图为「二分图」。

形式化地,设图 \(G=(V,E)\),若 \(V=X\cup Y,X\cap Y=\varnothing\),则对于 \(\forall (u,v)\in E\)\(u\in X,v\in Y\),则 \(G\) 为二分图。

常见的二分图有:树、偶环、网格。

如果已知 \(G=(V,E),V=X\cap Y,X\cap Y=\varnothing\),则二分图 \(G\) 也可记作 \(G=(X,Y,E)\)

性质

  1. 二分图可以仅用两种颜色对所有节点染色,且没有边连接颜色相同的点。
  2. 二分图中不存在奇环。
  3. 二分图的各连通块互不影响。

性质 \(1\) 是显然的,且性质 \(1\) 与二分图的定义等价。

对于性质 \(2\),考虑奇环不满足性质 \(1\)

判定

常用的判定方法有:

  1. 可以仅用两种颜色对所有节点染色,且没有边连接颜色相同的点的图为二分图。
  2. 不存在奇环的图为二分图。

判定方法 \(1\) 与定义等价。

对于判定方法 \(2\),考虑到原图要么是树,要么是含有偶环的图。前者是二分图,而后者也是,因为将偶环缩为一个点不影响其是否为二分图,则等价于一棵树。

实际应用中,就常常通过在图上染色的方式来判定二分图——间隔染色,如果当前节点 \(x\) 应该染的颜色 \(\textit{color}\) 与之前染的颜色 \(\textit{vis}_x\) 不同,则不为二分图。

SP3377 BUGLIFE - A Bug's Life

虫子还有同性恋。

给定 \(n\) 个点,\(m\) 条边,求能否将所有节点划分为两个部分,使得所有边连接的节点都处于不同部分,多测。如果可以,输出 No suspicious bugs found!,否则输出 Suspicious bugs found!

显然是二分图判定问题。注意要对所有连通块进行 DFS 判断。时间复杂度 \(\mathcal O(n+m)\)

//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
constexpr const int N=2000,M=1e6;
int n;
vector<int>g[N+1];
int vis[N+1];
void dfs(int x,int fx,int color,bool &ans){
	if(vis[x]){
		if(vis[x]!=color){
			ans=true;
		}
		return;
	}
	vis[x]=color;
	for(int i:g[x]){
		if(i==fx){
			continue;
		}
		dfs(i,x,color^3,ans);
		if(ans){
			return;
		}
	}
}
int main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	
	int T;
	cin>>T;
	for(int i=1;i<=T;i++){
		int m;
		cin>>n>>m;
		for(int i=1;i<=n;i++){
			g[i].resize(0);
		}
		while(m--){
			int u,v;
			cin>>u>>v;
			g[u].push_back(v);
			g[v].push_back(u);
		}
		bool ans=false;
		memset(vis,0,sizeof(vis));
		for(int i=1;i<=n;i++){
			if(!vis[i]){
				dfs(i,0,1,ans);
			}
		}
		cout<<"Scenario #"<<i<<":\n";
		if(ans){
			cout<<"Suspicious bugs found!\n";
		}else{
			cout<<"No suspicious bugs found!\n";
		}
	}
	
	cout.flush();
	
	/*fclose(stdin);
	fclose(stdout);*/
	return 0;
}

二分图应用

二分图性质简单,有诸多应用。

二分图最大匹配

图的匹配

无向图 $G=(V,E)$ 的匹配为边集 $M\subseteq E$,且 $M$ 中的边没有共顶点。

即从图中选择若干条没有共顶点的边。

posted @ 2025-11-23 21:39  TH911  阅读(4)  评论(0)    收藏  举报