首页 > 其他分享 >二分图

二分图

时间:2024-09-20 15:35:38浏览次数:9  
标签:二分 匹配 int dfs vis col

定义

节点由两个集合组成,且两个集合内部没有边的图

性质

  • 无奇环
  • 每条边都是从一个集合走向另一个集合。

二分图判定

使用染色法

进行 \(dfs\),为图进行黑白染色,若可以完成则该图是二分图。

bool vis[N];//0:未染色,1:黑色,2:白色
bool flag= 1;
void dfs(int x)
{
	for (auto y : v[x])
	{
		if (!col[y]) col[y] = 3-col[x],dfs(y);
		else if (col[y] != 3-col[x]) flag = 0;
	}
}

二分图最大匹配

即找到最多条边使两个集合的点匹配。

使用匈牙利算法

算法思想是在已有的匹配基础上考虑能否一种新的匹配方式使得匹配数 + 1,俗称增广路。

bool dfs(int x)
{
	for (auto y : v[x])
	{
		if (vis[y]) continue;
		if (!p[y] || dfs(p[y])) 
		{
			p[y] = x;
			return 1;
		}
	}
	return 0;
}

例题

P3386

P3386

没什么好说的,板子题。

int n,m,e;

vector<int> v[N];

int p[N];
bool vis[N];
void add(int x,int y){v[x].push_back(y);}
bool dfs(int x)
{
	for (auto y :v[x])
	{
		if (vis[y]) continue;
		vis[y] = 1;
		if (p[y]==0 || dfs(p[y]))
		{
			p[y] = x;
			return 1;
		}
	}
	return 0;
}

int main()
{
	n = read(),m = read(),e = read();
	for (int i = 1;i <= e;i++)
	{
		int u = read(),v = read();
		v += n;
		add(u,v);
		add(v,u);
	}
	int ans = 0;
	for (int i = 1;i <= n;i++)
	{
		memset(vis,0,sizeof vis);
		ans += dfs(i);
	}
	cout << ans << endl;
	return 0;
}

P2071

P2071

挺有意思的二分图匹配变种题。

与二分图正常匹配唯一区别是可以一个点匹配两个点。

做法很简单,就是将一边的点复制一份,这样就变成了一个点匹配一个点了。

CF1139E

CF1139E

感觉是个非常好的题。

非常适合作为二分图的练习题。

我们先考虑将操作倒序,此时变成每次加入一个学生。

然后注意到”校长将会从每个社团中选出一个人“,若我们将能力值与拥有该能力值的学生所属社团连边,似乎就变成了一个二分图匹配的问题。

但是 \(mex\) 还是不好求。

想法 \(1\) 是每次加入后二分 \(mex\) 的值,然后判断能否做到完全匹配。

时间复杂度 \(O(n^3 \log n)\),显然过不去。

考虑优化,我们发现每次二分判断是否是完全匹配时都会遍历 \([0,mid]\) 跑 \(dfs\)。

那么我们其实可以从 \(0\) 开始往后枚举,直到无法找到增广路便 \(break\) ,这样就省去了一个二分。

时间复杂度 \(O(n^3)\),还是过不去。

注意到我们每次加入一条边时对于原来已有的匹配是没有影响的,即答案满足单调性。

那么我们每次加边的时候就不需要从 \(0\) 开始往后遍历,直接从上一次的 \(mex\) 开始即可。

时间复杂度分析:整个算法跑下来相当于只跑了一遍匈牙利,复杂度 \(O(n^2)\)。本题搞定!

标签:二分,匹配,int,dfs,vis,col
From: https://www.cnblogs.com/codwarm/p/18339605

相关文章

  • 算法随笔——wqs二分
    学习链接学习链接应用条件选择恰好\(x\)个物品,求最优值设\(x\)对应最优值\(f_x\),\((x,f_x)\)在图像上呈现为凸包。无数量限制问题简单可做问题转化有\(n\)个物品,恰好选\(m\)个,计算最优值。做法例题模版题:P2619......
  • 【oj刷题】二分查找篇:二分查找算法的原理和应用场景
    前言:二分查找算法,又称折半查找算法,是一种在有序数组中查找特定元素的高效查找方法。它通过将搜索区间不断缩小一半,从而在对数时间内找到目标元素。二分查找是基于分治策略的一种典型应用,能够高效的处理许多问题,下面我们就来看一下二分查找算法的原理和应用场景目录一、什......
  • 算法设计与分析(二分查找算法
    目录二分查找算法详解引言算法步骤代码实现注意事项结论小结:二分查找算法详解引言二分查找算法是一种在有序数组中查找特定元素的搜索算法。它通过不断将数组分成两半,缩小搜索范围,从而快速定位到目标元素的位置。二分查找算法的时间复杂度为O(logn),其中n是数组的长度。算法步骤......
  • 算法学习每日一题之2332. 坐上公交的最晚时间:二分答案 & 贪心双指针
    Problem:2332.坐上公交的最晚时间人话题意:你是一个懒惰的人,虽然你要赶公交车,但你想多睡会,恰好你知道每辆车的发车时间buses和每辆车容capacity,和每个乘客乘车的时间passenger,旨在求可以赶上公交车的最晚出发时间。思路一:二分答案求最晚能满足赶上公交的时间,可以发现......
  • 算法笔记2:二分
    二分二分可以求得满足条件的左边界或右边界,如下图所示查找左边界(绿色区域的最左边):intSL(intl,intr){while(l<r){intmid=l+r>>1;if(check(mid))r=mid;elsel=mid+1;}re......
  • 【每日一题】LeetCode 2332.坐上公交的最晚时间(数组、双指针、二分查找、排序)
    【每日一题】LeetCode2332.坐上公交的最晚时间(数组、双指针、二分查找、排序)题目描述给你一个下标从0开始长度为n的整数数组buses,其中buses[i]表示第i辆公交车的出发时间。同时给你一个下标从0开始长度为m的整数数组passengers,其中passengers[j]表示第......
  • 代码随想录算法训练营第一天|704二分查找 27移除数组 977.有序数组的平方
    704二分查找给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。示例1:输入:nums=[-1,0,3,5,9,12],target=9输出:4解释:9出现在nums中并且下标为4示例 2:输......
  • 二分详解——学习笔记
    首先,使用二分有几个前提:具有单调性要求“最小的最大”或“最大的最小”其次,还要分清楚二分查找与二分答案的区别:二分查找:在某区间使用二分的思想进行查找二分答案:在答案的区间中使用二分的思想并判断从而找到最优解同时还要处理好二分的边界。接下来来理解一下......
  • 二分查找法
    #include<stdio.h>intmain(){   intarr[]={1,2,3,4,5,6,7,8};//有序数组   intn=sizeof(arr)/sizeof(arr[0]);//数组中元素的数量   intk=10;   //intn1=sizeof(arr);//数组总大小   //intn2=sizeof(arr[0]);//单个元素大小......
  • 学习笔记-二分图
    二分图二分图当且仅当图中没有奇数环.染色法//染色法模板intn;//n表示点数inth[N],e[M],ne[M],idx;//邻接表存储图intcolor[N];//表示每个点的颜色,-1表示未染色,0表示白色,1表示黑色//参数:u表示当前节点,c表示当前点的颜色booldfs(intu......