二分图学习笔记

反正就给自己看,那么就随便写写

吐槽一下CPP为什么这么迟才教二分图

一个图是二分图,那么这个图就一定可以分成两部分,这两部分的点一定不会与自己的只一部分直接相连

二分图的判断非常水,直接黑白染色就可以了

只要没有奇环(我tm打qihuan都比打jihuan要快)就可以了

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

然后就是二分图的的最大匹配问题

解决二分图的最大匹配问题,一般使用匈牙利算法

匈牙利算法用于解决二分图的最大匹配和最大权匹配的问题

其实就是找到很多的没有匹配的路,然后让没有匹配的路和匹配的路连在一起,然后翻转过后让长度增加,这就是基本思路。

那么我们都从左边开始找,然后通过找一个点来跳转,每次都只更新一条边,从1到n都更新一遍就能找到最大匹配了

代码:

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)\)\((u,v)\) 的子图称为相等子图。

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

那么我们就可以考虑从调整可行项标的角度入手

我们要让所有点都匹配上,所以我们考虑从每一个点开始枚举,直到找到可以匹配的情况

我们先把左边的(去匹配)的点找出来,然后把最大的边权设为值,枚举每一个点,如果都没法拓展,那么就把距离连接最接近的点找到,得到这个点的差值,然后让目前连接出来的这个图中,所有左边的点减去这个差值,右边的点加上这个差值,这样就维持了整个图的平衡,然后又可以继续连接,由于每次至少会连一个点,所以时间复杂度也是 \(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;
}

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

然后二分图的内容就差不多了哈哈,直接整完了,感觉CPP放的二分图都还算好写

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

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

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

我的天哪Sunday大人就这么水灵灵的写完了

posted @ 2025-11-28 09:37  huhangqi  阅读(0)  评论(0)    收藏  举报
/*
*/