二分图刷题笔记

二分图定义:
可以所有点划分到两边去,使得所有的边都是在集合之间的,
且在左右两个集合中不存在其他边

性质:

一定不含有奇数环,可能包含长度为偶数的环,不一定是连通图

if 是二分图的话,一定不含奇数环
if 是一个图含有奇数环打得话,一定不是二分图

性质证明(图解):

 

性质应用:

1.AcWing 860. 染色法判定二分图 - AcWing

思路:

奇数环:环中边的数量是奇数 
分组(染色) - - 可以用 1/2 表示不同颜色(组),0表示未染色(分组)

//由于某个点染色成功不代表整个 图就是二分图,
只有当某一个点染色失败的时候才能理科break /return
染色失败代表相邻两个点染上了不同的颜色

这里的染色法可以用dfs遍历所有边也可以dfs,代码如下

bool dfs(int u, int col) {
	st[u] = col;
	for (int i = h[u]; ~i; i = ne[i]) {
		int  j = e[i];
		if (!st[j]) {
			if (!dfs(j, 3 - col))return false;
		}
		else if (st[j] == col)return false;
	}
	return true;
}
bool  bfs(int u){
    int hh=0,tt=0;
    q[0]={u,1};
    st[u]=1;
    while(hh<=tt){
    PII t=q[hh++];   
        int u=t.first,c=t.second;
        for(int i=h[u];~i;i=ne[i]){
            int j=e[i];
            if(!st[j]){
            st[j]=3-c;   
            q[++tt]={j,3-c};
            }else if(st[j]==c)return false;
        }
    }
    return true;
}

那么当 limit∈[ans,109]limit∈[ans,109] 时,所有边权大于 limitlimit 的边,必然是所有边权大于 AnsAns 的边的子集,因此由此构成的新图也是二分图。
当 limit∈[0,ans−1]limit∈[0,ans−1] 时,由于 ansans 是新图可以构成二分图的最小值,因此由大于 limitlimit 的边构成的新图一定不是二分图。

2.257. 关押罪犯 - AcWing题库

//思路: 二分 +染色法判断二分图,枚举每一种可能结果,找到临界点即为所求

关押罪犯:
题意: n个罪犯里面有m条仇恨值关系,把n个罪犯分到不同的
两个监狱中,使得他们之间的仇恨值尽可能小,
要你求出一个监狱里面的仇恨值之和

题意抽象:
将罪犯当做点,罪犯之间的仇恨当做点与点之间无向边,
边的权重就是点之间的仇恨值
原题变成:
将所有点分成两组,就两组中的权重最大值的尽可能小

我们可以在[0,1e9]之间枚举最大 边权  lim
然后把所有> lim的边都放到 组间,把所有<=lim的边都放到组内
然后判断这样的一个图是否是二分图(这里我们可以使用染色法判断)

同时由于1e9 过大了,我们考虑二分这个区间,加速寻找ans

证明(mid<ans)>mid 的图是> ans的子集

 

3.AcWing 861. 二分图的最大匹配 - AcWing (匈牙利板子)

匹配:在图论中,一个「匹配」是一个边的集合,其中任意两条边都没有公共顶点。
最大匹配:一个图所有匹配中,所含匹配边数最多的匹配,称为这个图的最大匹配。


完美匹配:如果一个图的某个匹配中,所有的顶点都是匹配点,那么它就是一个完美匹配。


交替路:从一个未匹配点出发,依次经过非匹配边、匹配边、非匹配边…形成的路径叫交替路。
增广路:从一个未匹配点出发,走交替路,如果途径另一个未匹配点(出发的点不算),则这条交替 路称为增广路,如下。

 

 

 

代码模版:

bool find(int u) {
	
	// 遍历所有她喜欢的女孩:
	for (int i = h[u]; ~i; i = ne[i]) {
		int j = e[i];
		if (!st[j]) { //if在这轮匹配中女孩未被预定
			st[j] = true;//那x就预定这个女孩
			//如果这个女孩没有npy 或者他的这个男朋友可以换个女朋友
			//那么x就有机会啦!!!
			if (!match[j] || find(match[j])) {
				match[j] = u;
				return true;
			}
		}
	}
	//可怜的单身狗,要光棍一辈子咯
return false;
}

4.372. 棋盘覆盖 - AcWing题库

本题难点在于如何抽象出模型,即怎么把矩形中的点分成相邻两种不同的点

原题意: 
矩形中最多放多少栈2*1的卡片,使得卡片之间不重叠

抽象题意:
把一个点和他相邻的点(格子)连上一条边,问:
最多选出来有多少 条边,使得选出的边时没有公共点的
--  最大匹配  --匈牙利解决

但是使用匈牙利打得前提是二分图
那么我们这样染色: 
对于一个格子坐标 x,y  x+y 是奇数的放一块,是偶数的放一块
这样我的二分图就得到了

//这里的find 函数代码由一维改为二维而已,思路试试一样的

 

bool find(int x,int y) {
	for (int i = 0; i < 4; ++i)
	{
		int a = x + dx[i], b = y + dy[i];
		if (a<1 || a>n || b<1 || b>n)continue;
		if (st[a][b] || g[a][b])continue;
		st[a][b] = true;
		PII t = match[a][b];
		if (t.x == 0 || find(t.x, t.y)) {
			match[a][b] = {x,y};
			return  true;
		}
	
	}

	return false;
}

5.376. 机器任务 - AcWing题库

匈牙利 求解:  
最小点覆盖 、最大独立集 、最小路径点覆盖(最小路径重复点覆盖)
最大匹配数= 最小点覆盖 =总点数 -最大独立集 = 总点数-最小路径点覆盖

本题主要考察二分图性质: 二分图中  最少点覆盖 == 最大匹配数 

题意:

对于灭国任务有 a,b 两台机器可以完成,但是每个任务i a需要在a[i]模式上完成,

b需要在b[i]模式上完成,换模式需要重启,求最少重启次数

抽象题意:

开始 a,b都是0 不需要代价,把每个任务抽象一条边,做一个任务(只需要经过边上两个端点之一即可) == 选择边上的某个点:

那么问题就转换为在剩下的  n+m-2中最少选择几个点可以把,所有边全部覆盖住--最少点覆盖

而二分图中  最少点覆盖 == 最大匹配数 

so 问题得解

6.378. 骑士放置 - AcWing题库

题意: 问棋盘上最多能放多少个不能互相攻击的骑士(国际象棋的“骑士”,类似于中国象棋的“马”,按照“日”字攻击,但没有中国象棋“别马腿”的规则)。

走法图解: 

so 我们有发现能走的点是 i+j 为奇数的 白格子,那么有变成二分图的问题了-- 

抽象题意: 
最多可以选出多少个点使得 这些点之间是不能相互攻击到的
等价于,选出最多的点使得这些点之间没有边 --最大独立集

最大独立集 定义:
选出最多的点,使得选出的点之间(内部)没有边

最大团:--二者互补
选出最多的点,使得选出的点之间(内部)有边
//原图的最大独立集 和补图的最大团相等

关联:

在二分图中求最大独立集 --- 
选出最多的点使得点之间无边 
== 去掉最少的点,把所有边破坏掉
==求最小点覆盖 == 求最大匹配

7.379. 捉迷藏 - AcWing题库

结论:

1.最少路径点覆盖=总点数- 最大匹配

2.拓展:
最小路径重复点覆盖:在最小路径覆盖问题的基础上,去掉互不相交。

结论:记原图G,求传递闭包后的图G’,则G的最小路径重复点覆盖=G’的最小路径覆盖

//求传递闭包
	for (int k = 1; k <= n; ++k)
		for (int i = 1; i <= n; ++i)
			for (int j = 1; j <= n; ++j)
				g[i][j] |= g[i][k] & g[k][j];

在原来的基础上多求一个传递闭包 即可求出最短路径重复点覆盖

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值