二分图学习笔记

发现自己当时写这个学习笔记的时候精神状态好像不太正常,现在改了一下才搬过来。

一个图是二分图,就一定能分成两部分,而且每部分的点绝不会和自己这一部分的点直接相连。

二分图的判断非常水,直接黑白染色就行了。只要没有奇环就可以了。

然后就会有很多板子题了。

接着就是二分图的最大匹配问题。解决二分图的最大匹配,通常用匈牙利算法。匈牙利算法常用于解决二分图的最大匹配以及最大权匹配问题。

其实就是找到很多未匹配的边,然后让未匹配的边与已匹配的边交替相连,再把整条路径翻转,让匹配数增加,这就是基本思路。我们从左边每个点出发,尝试找增广路,每次只更新一条路径,把所有左边点都跑一遍就能得到最大匹配了。

代码:

bool dfs(int p){
	if(vis[p])return false;
	vis[p]=1;
	for(int i:e[p]){
		if(!a[i]||dfs(a[i])){
			a[i]=p;
			return true;
		}
	}
	return false;
}
void solve(){
    for(int i=1;i<=n;i++){
		memset(vis,0,sizeof(vis));
		if(dfs(i))ans++;
	}
}

补充几个相关的性质:

Kőnig 定理:二分图中,最小点覆盖的顶点数量等于最大匹配的边数量。证明显然?

然后是二分图上的最大独立集。这个可以根据 Kőnig 定理 推出来:最大独立集 = 所有点数 - 最小点覆盖数。证明似乎也是显然的?

于是就可以用最大匹配的边数去求这些东西了。

还有有向无环图上的最小路径覆盖,其实路径数也是顶点数减去最大匹配。通过将每个点拆成出点和入点建出二分图,求出最大匹配后,就能把匹配边合并成若干条长路径,剩下未匹配的点各自独立,这样就能搞出来了。

然后是最大权匹配问题。

我们需要给每个节点 \(i\) 分配一个顶标 \(l(i)\),对于所有边 \((u,v)\) 满足 \(w(u,v) \le l(u)+l(v)\)

在一组可行顶标下,原图的生成子图(包含所有点)中,只保留满足 \(w(u,v)=l(u)+l(v)\) 的边,称为相等子图。

显然可得定理:对于某组可行顶标,如果其相等子图存在完美匹配,那么该匹配就是原二分图的最大权完美匹配。

那么我们就可以从调整可行顶标的角度入手。要使得所有点都匹配上,就从每个点开始枚举,直到找到匹配为止。

先把每个左边点的顶标初始化为它连出的最大边权,然后依次枚举每个点。如果当前点无法找到增广路,就找出与连接最接近的差值 \(d\),然后让所有访问过的左边点顶标减去 \(d\),右边点顶标加上 \(d\),这样既维持了平衡,又能引入新的相等边继续匹配。因为每次调整至少会增加一条新边,所以时间复杂度也是 \(O(n^3)\)

这样直接就搞出来了哈哈哈,我简直是个天才。

代码:

bool dfs(int p){
	if(visx[p])return false;
	visx[p]=1;
	for(int i=1;i<=k;i++){
		if(!visy[i]&&lx[p]+ly[i]==e[p][i]){
			visy[i]=1;
			if(!a[i]||dfs(a[i])){
				a[i]=p;
				return true;
			}
		}
		else if(!visy[i])d=min(d,lx[p]+ly[i]-e[p][i]);
	}
	return false;
}
int km(){
	memset(ly,0,sizeof(ly));
	for(int i=1;i<=k;i++){
		lx[i]=e[i][1];
		for(int j=2;j<=k;j++)lx[i]=max(lx[i],e[i][j]);
	}
	memset(a,0,sizeof(a));
	for(int i=1;i<=k;i++){
		while(1){
			memset(visx,0,sizeof(visx));
			memset(visy,0,sizeof(visy));
			d=2e9;
			if(dfs(i))break;
			for(int j=1;j<=k;j++){
				if(visx[j])lx[j]-=d;
				if(visy[j])ly[j]+=d;
			}
		}
	}
	int ans=0;
	for(int i=1;i<=k;i++)ans+=e[a[i]][i];
	return ans;
}

当然这是求最大值的做法,最小值有个比较简单的方法:直接把边权搞成负数,属于是简单无脑了。

这样二分图的内容就差不多了哈哈,直接整完了。

那么再来研究研究怎么建图吧。

首先最常见的,就是直接让你匹配两者关系的,直接建图就可以了。

然后如果是普通图,但出度入度最多只有 1 的构造问题,那也可以通过二分图匹配来解决。

posted @ 2026-06-11 21:29  huhangqi  阅读(7)  评论(0)    收藏  举报