首页 > 其他分享 >图论连通性相关

图论连通性相关

时间:2024-09-04 23:14:04浏览次数:4  
标签:图论 Set 连通性 int void 查集 init inline 相关

并查集

普通并查集:

路径压缩写法:

struct Union_Find_Set {
	int f[N];
	inline void init() {
		for(int i = 1 ; i <= n ; ++ i)
			f[i] = i;
	}
	inline int find(int x) {
		if(x != f[x]) f[x] = find(f[x]);
		return f[x];
	}
	inline void merge(int a, int b) {
		int x = find(a), y = find(b);
		f[y] = f[x];
	}
} Set;

启发式合并写法:

struct Union_Find_Set {
	int f[N], h[N];
	inline void init() {
		for(int i = 1 ; i <= n ; ++ i)
			f[i] = i, h[i] = 1;
	}
	inline int find(int x) {
		if(x != f[x]) return find(f[x]);
		return f[x];
	}
	inline void merge(int a, int b) {
		int x = find(a), y = find(b);
		if(h[x] > h[y]) f[y] = f[x];
		else {
			f[x] = f[y];
			if(h[x] == h[y]) ++ h[y];
		}
	}
} Set;

这是按秩合并的,当然也可以按元素个数启发式合并。

这俩可以写一起:

struct Union_Find_Set {
	int f[N], h[N];
	inline void init() {
		for(int i = 1 ; i <= n ; ++ i)
			f[i] = i, h[i] = 1;
	}
	inline int find(int x) {
		if(x != f[x]) f[x] = find(f[x]);
		return f[x];
	}
	inline void merge(int a, int b) {
		int x = find(a), y = find(b);
		if(h[x] > h[y]) f[y] = f[x];
		else {
			f[x] = f[y];
			if(h[x] == h[y]) ++ h[y];
		}
	}
} Set;

要注意的是 find 里面的 ifreturn 的复杂度是假的。

例题

多而且杂,一般可用并查集维护的性质很突出。

CF217A Ice Skating

vjudge

很傻逼的网格图问题。

同列 / 同行放到一个连通块里面,并查集轻松维护。

P2658 汽车拉力比赛

有点傻逼的网格图问题。

分析:

1.由于题目要求保证所有路标相互可达,于是想到并查集

2.发现对于任意一个 \(D\),模拟一次都是 \(O(nm)\) 的,且 \(D\) 越大所有路标越可能相互可达,考虑二分 \(D\)

3.每次扫网格图,对于每个点,若和其相邻点高度差小于当前二分的 \(D\) 则连边,最后判断所有路标是否在一个连通块内

4.坐标 \((x, y)\) 可以改写成 \((x - 1)m + y\)

时间复杂度 \(O(nm\log V)\),其中 \(V\) 为值域。

check 部分代码:

inline bool check(int x) {
	init();
	
	for(int i = 1 ; i <= n ; ++ i)
		for(int j = 1 ; j <= m ; ++ j) {
			//to(i, j) 为坐标的转换函数。
			
			int pos = to(i, j), pos1 = to(i + 1, j), pos2 = to(i, j + 1);
			
			if(i + 1 <= n && abs(a[pos] - a[pos1]) <= x) merge(pos, pos1);
			if(j + 1 <= m && abs(a[pos] - a[pos2]) <= x) merge(pos, pos2);
		}
	
	int Fa = 0;
	
	for(int i = 1 ; i <= n ; ++ i)
		for(int j = 1 ; j <= m ; ++ j)
			if(vis[to(i, j)]) {
				if(! Fa) Fa = find(to(i, j));
				else if(Fa != find(to(i, j))) return false;
			}
	
	return true;
}

扩展域并查集:

应用于有多个集合且有关系时。

另外这东西还能判二分图。

具体的就是建多个并查集。

带权并查集:

维护边的时候带权。

一般用路径压缩能够减少维护的信息。

合并时候的权值更新可以用向量去理解。

struct Union_Find_Set {
	int f[N], val[N];
	inline void init() {
		memset(val, 0, sizeof val);
		for(int i = 1 ; i <= n ; ++ i)
			f[i] = i;
	}
	inline int find(int x) {
		if(x != f[x]) val[x] += val[f[x]], f[x] = find(f[x]);
		return f[x];
	}
	inline void merge(int a, int b, int Val) {
		int x = find(a), y = find(b);
		f[y] = f[x], val[y] = -val[a] + Val + val[b];
	}
} Set;

当然操作不仅限于加法。

可撤销并查集

按加入的时间从后往前撤销。

用启发式合并写法实现(路径压缩改变树的形态),同时维护上述操作可以用栈来实现。

那么对于一条边为什么一定要是有顺序的撤销呢?如果不是按出栈的顺序撤销,那么必定有比他晚一些连边的集合的大小没法维护,所以必须按出栈顺序撤销。

struct Union_Find_Set {
	int f[N], h[N];
	stack<int> s;
	inline void init() {
		memset(val, 0, sizeof val);
		for(int i = 1 ; i <= n ; ++ i)
			f[i] = i, h[i] = 1;
	}
	inline int find(int x) {
		if(x != f[x]) return find(f[x]);
		return f[x];
	}
	inline void merge(int a, int b) {
		int x = find(a), y = find(b);
		if(h[x] > h[y]) f[y] = f[x];
		else {
			f[x] = f[y];
			if(h[x] == h[y]) ++ h[y];
		}
	}
	inline void Delete() {
		if(s.empty()) return;
		int k = s.top(); s.pop();
		h[f[k]] -= h[k], f[k] = k;
	}
	inline void revoke(int x) {while(s.size() > x) Delete();}
} Set;

标签:图论,Set,连通性,int,void,查集,init,inline,相关
From: https://www.cnblogs.com/endswitch/p/18397498

相关文章

  • 代码随想录训练营 Day50打卡 图论part01 理论基础 98. 所有可达路径
    代码随想录训练营Day50打卡图论part01一、理论基础DFS(深度优先搜索)和BFS(广度优先搜索)在图搜索中的核心区别主要体现在搜索策略上:1、搜索方向:DFS:深度优先,一条路走到黑。DFS从起点开始,选择一个方向深入到底,遇到死胡同再回溯,换一个方向继续探索。这种方式适合解决路径......
  • 使用python虚拟环境相关的一点建议
    1.不要直接使用base虚拟环境为某个项目所用。理由如下:全局依赖:base环境中的包是全局的,所有项目都会共享这些包。如果不同项目需要不同版本的同一个包,可能会导致依赖冲突。版本控制:在base环境中,更新一个包可能会影响其他项目的正常运行。或者删除一个包,也可能对其他项目造成......
  • [Python图论]在用图nx.shortest_path求解最短路径时,节点之间有多条边edge,会如何处理?
    问:在使用图求最短路径时,如果节点之间有多条路径,shortest_route=nx.shortest_path(G,source=start_node,target=end_node,weight='length')会如何处理,会自动选择最短那条吗?#输出图G各节点之间有多少条边edge,并给出其长度Edgesbetween103928and25508583:共2条Edge......
  • audio元素与audio对象相关方法和配置项
    <audio>元素属性:src:指定音频文件的来源。controls:显示音频播放器的默认控件,如播放、暂停、音量调节等。autoplay:自动播放音频文件,一旦页面加载完毕,音频就会开始播放。loop:音频播放完毕后自动重新播放。muted:默认静音播放音频。preload:设置音频在页面加载时的......
  • IIS相关错误报错汇总整理及解决方案
    解决方案400BadRequest:检查请求是否包含错误的信息或格式。401Unauthorized:确认是否已经进行了身份验证。403Forbidden:检查是否有足够的权限访问资源。404NotFound:确认请求的URL是否正确,资源是否存在。500InternalServerError:检查服务器日志,寻找错误信息。503Ser......
  • pbootcms模板内页如何调用相关文章
    在PbootCMS中,可以使用 {pboot:list} 标签来调用相关文章。相关文章通常是根据分类或其他条件筛选出来的文章。下面是一个详细的示例,展示如何在模板内页调用相关文章。示例代码假设你想在一个文章详情页中调用与当前文章相同分类下的其他文章,可以使用以下代码:html {pb......
  • 【广告变现】解读国内广告联盟相关知识
    更多知识推荐:关于广告的基础知识你了解多少?-游戏干饭之家在广告系统中广告投放逻辑怎么实现的-游戏干饭之家对于做IAA游戏的开发者来说可能比较熟悉文中所说的广告联盟,国内来看,头部互联网腾讯、字节跳动、百度、阿里以及快手等都搭建了自己的广告联盟平台。1.广告联盟......
  • TIE cell相关
    PR工具使用TIEcell的前提条件:1,DC后的netlist中自带TIECELL或者存在1‘b0,1'b1这种接0或者接1的代码2,在place阶段设置set_dont_touch[get_lib_cells*/TIE01*]false(在place阶段对TIEcell可进行优化)set_lib_cell_purpose-includeoptimization[get_lib_cells*/TIE01*](在p......
  • 第十一章 图论 Part1
    任务797.所有可能的路径给你一个有n个节点的有向无环图(DAG),请你找出所有从节点0到节点n-1的路径并输出(不要求按特定顺序)graph[i]是一个从节点i可以访问的所有节点的列表(即从节点i到节点graph[i][j]存在一条有向边)。思路题目所给的图的表示是邻接表,题意就是找到......
  • 代码随想录day50 || 图论基础
    图论基础定义图的构造方式1,邻接矩阵矩阵位置array[i][j]=k,i表示节点i,j表示节点j,[i][j]表示i-->j存在一条边,k表示的是边的权重邻接矩阵的优点:表达方式简单,易于理解检查任意两个顶点间是否存在边的操作非常快适合稠密图,在边数接近顶点数平方的图中,邻接矩阵是一种空......