二分图 学习笔记

相关链接

题单:https://www.luogu.com.cn/training/79728

文章:https://www.cnblogs.com/streamazure/p/13778319.html

https://oi-wiki.org/graph/bi-graph/

二分图的判定

如果一张无向图,可以将图中的点分成两个集合 \(A,B\),使得同一个集合的所有点互不相交,那么它即是一个二分图,\(A\) 是集合的左部,\(B\) 是集合的右部。
image
如图即是一个二分图,\(A\) 包含了 \({1,4,6}\)\(B\) 包含了 \(2,3,5\)

二分图的性质有这些:

  • 对二分图进行染色,相邻的点不可以染同色,用两个颜色即可覆盖这个图。
  • 二分图没有长度为奇数的环,因为每一次都会从一个一个集合到另一个集合。

我们可以运用这些性质来进行判定。每次从一个未染色点出发,如果有颜色而且是同色,那么不是二分图,否则给相邻的点染上反色,并继续向下搜索。
关联题目:P1330 封锁阳光大学

代码
#define maxn 10050
int n,m;
vector<int>G[maxn];
int col[maxn],bel[maxn];
int sum[3][maxn];
bool flg=0;
bool dfs(int now,int c,int nth) {
	col[now]=c; bel[now]=nth;
	for(auto nxt:G[now]) {
		if(col[nxt]==c) return 0; 
		if(!col[nxt]&&!dfs(nxt,3-c,nth)) return 0; 
	}
	return 1;
}
signed main() {
	in2(n,m);
	For(i,1,m) {
		int a,b;
		in2(a,b);
		pb(G[a],b);
		pb(G[b],a);
	}
	int tot=0;
	For(i,1,n)
		if(!col[i]) 
			if(!dfs(i,1,++tot))
				return cout<<"Impossible",0;
	int cnt=0;
	For(i,1,n) sum[col[i]][bel[i]]++;
	For(i,1,tot) cnt+=min(sum[1][i],sum[2][i]);
	cout<<cnt;
}

二分图最大匹配

匹配或是独立边集是一张图中不具有公共端点的边的集合。
左部的点集 \(A\) 和右部的点集 \(B\),枚举左部的点,尝试向右寻找一个点 \(B_i\),使得 \(B_i\) 要么暂时没有被其他左部的点选中,要么可以使得改变其他的左部点的匹配方式,使得 \(B_i\) 未被选中。
由于最大匹配的边数是确定的,所以我们可以随便选一个起点。
时间复杂度 \(O(nm)\),其中 \(n\) 是点数,\(m\) 是边数

关联题目:P3386 【模板】二分图最大匹配

代码
#define maxn 510
int n,m,e,ans,G[maxn][maxn],to[maxn],u,v;
bool vis[maxn];
bool dfs(int now) {
	For(i,1,m) if(G[now][i]&&!vis[i]) {
		vis[i]=1;
		if(!to[i]||dfs(to[i])) return to[i]=now,1;
	}
	return 0;
}
signed main() {
	in3(n,m,e);
	For(i,1,e) in2(u,v),G[u][v]=1;
	For(i,1,n) m0(vis),ans+=dfs(i);
	cout<<ans;
}
posted @ 2024-10-14 09:24  coding_goat_qwq  阅读(8)  评论(0编辑  收藏  举报