ACM第七周总结-并查集

目录

1.比赛并查集

2.洛谷并查集训练

小总结1:

小总结2:

 总结3:

总结4:

拓扑排序: 

  • 这周我主要看的是题目,了解到并查集的基本套路,首先先要了解并查集的基本构成就是找祖先,合并祖先,以及基本的初始化。其实看的大多数题目中主要也是最小生成树的一个模板,即kruskal,这是利用并查集来实现的最小生成树的一个算法,具体实现方法也比较简单,可以看我的

淼淼Kruskal算法_钟一淼的博客-CSDN博客应用场景:还是说建公路,电路网等如何缩短距离,减小成本。算法过程:运用了并查集的找祖先以及如何合并->淼淼的并查集_钟一淼的博客-CSDN博客主要还是看图示,kruskal算法一般会定义结构体:struct node{ int x; int y; int side;//记录边权值}bool cmp(node x,node y){ return x.side>y.side;}首先看图,我们定义了这个结构体,然后进行...https://blog.csdn.net/m0_64045085/article/details/123807667?spm=1001.2014.3001.5502

  • 关键点在于对于n条路径而言,建立n-1条边才能让整个树连通,所以可以用来判断所建的图是否连通,由于用sort排序对边权值进行排序这个原因,所以我们能够很快的找出路径最大的那个点,还有一些带权并查集的做法,结合例题来总结一下。

1.比赛并查集

  • 首先我想说的一个例题是今天星期三比赛的并查集的这个例题

Party - 洛谷https://www.luogu.com.cn/problem/CF177C1

  • 题意:
  • 就是求相互喜欢,没有讨厌的最大集合的集合内的个数。
  • 题解:
  • 其实实现起来并不复杂,只不过这次我们多了一个标记数组VIS,首先初始化,合并给出的值,不喜欢的数据,寻找两个人的祖先是否相同,不相同,不隶属于同一个集合,我直接就continue,如果祖先相同那就是隶属于同一个集合,标记该祖先,这时候我们就要想新的问题了,就是我们如何才能取到每一个集合里面的元素,于是我们新开一个数组,将每一个元素进行寻找祖先,然后++,这样我们就可以统计出来每个集合的个数就ok,然后就是最后一步,遍历,找每一个祖先,如果祖先不是自己,或者已经被不喜欢给标记过了,就跳过,max,取存储祖先数组的最大值,输出,撒花!
#include<iostream>
#include <cmath>
using namespace std;
int father[3000];
int cha[3000];
bool vis[3000];
int n, m, ans;
int find(int x)
{
	if (father[x] == x) { 
		return x;
	}
	return father[x] = find(father[x]);
}
void init() {
	for (int i = 1; i <= n; ++i) {
		father[i] = i;
	}
}
int main()
{
	int x, y;
	int t;
	cin >> n >> m;
	init();
	for (int i = 1; i <= m; i++) 
	{
		cin >> x >> y;
		father[find(x)] = find(y);//并查集合并
	}
	cin >> t;
	for (int i = 1; i <= t;i++)
	{
		cin >> x >> y;
		if (find(x) != find(y)) {
			continue;//祖先不相同,说明不在同一个集合当中
		}
		vis[find(x)] = 1;//标记这个有讨厌边权的祖先
	}
	for (int i = 1; i <= n; ++i) {
		cha[find(i)]++;//一共有多少个集合,并且这些集合里面的元素有多少个都给统计出来了
	}
 
	for (int i = 1; i <= n; ++i)
	{
		if (father[i] != i || vis[i]) {
			continue;
		}
		ans = max(ans, cha[i]);//取得这些条件的最大值
	}
	cout << ans << endl;}

2.洛谷并查集训练

其实有写一部分题解,但大部分都记在表格上了->并查集练习1_钟一淼的博客-CSDN博客

说几个觉得比较有意思的题

炸铁路 - 洛谷

这就是我一开始说的利用最小生成树进行操作,如果在炸了这条路之后图依然连通即我仍然可以合并n-1次,也是n-1条边,那么我炸毁这条公路的意义不存在,所以我在只需要找出我炸掉的这条边,保证这个最小生成树无法形成即可,输出这条路的两边,而且他们本身就可以在结构体中定义排序顺序,所以直接输出即可,(是不是非常的神奇)

[SCOI2005]繁忙的都市 - 洛谷

这道题就是利用了kruskal的特性,已经将边权值排好了序,所以能够实现最短,最优的连接路径,最后输出的那个值即是最大值。

小总结1:

所以我们可以利用kruskal这个sort的特性来判断许多题目所求的东西。

[USACO16OPEN]Closing the Farm S - 洛谷

这个题就比较值得揣摩的一个,因为我们是无法是直接拆分以一个完整的图的(可能也是我水平不够),所以我们要倒序来看,一开始只有一个农场是开放的,然后慢慢加边,判断是否是连通即可,所以说在判断连通图这方面,就是遍历看看是否是同一个祖先,使用一个祖先就是一张连通图,同属于一个集合,输出YES

小总结2:

判断连通图比较好用,祖先不同,一定不连通。

P1396 营救 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

 典型的一道对边权值进行排序,合并,然后当起点和终点连接时,输出边权值即为最大值。

 [USACO3.1]最短网络 Agri-Net - 洛谷

P2820 局域网 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

最小生成树模板题目

 总结3:

其实很多都是很一个套路,无非就是摆上模板,初始化,合并,找祖先,排序,无非就是计算总的边权值,即最少需要使用的建设的总值,还有一些有变化,不如局域网让求的是剪掉边的总值,无非就是总和减去建设的值嘛,还是换汤不换药的套路吧。

一中校运会之百米跑 - 洛谷

还看到了几道字符串类型的并查集题目,我的做法就是直接用map映射成数字然后建立并查集,该合并合并,该询问是否是一个集合(即是否是一个祖先)(STL大法)

P1197 [JSOI2008]星球大战 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

这个题还是刚刚典型的倒叙思维题目+求连通块个数=求每次加边之后究竟有多少个祖先,即可判断出连通图的多少,这个题与之前的题不同的是我们不了解打击了k次之后图的情况,所以我们需要先模拟一遍打击了k次后图的连通情况,然后再进行修复工作,判断连通图的个数即可。

总结4:

拆边+询问(比如轰炸,摧毁)就要想到用倒序的思维来做,如果最初的图是未连接的图,那就从头开始修复,判断祖先个数,即连通图个数(相对比较简单),如果说一开始并不是初始化的图,那就模拟轰炸了n次后的连通状况,然后再建边。

看了二十多道并查集大致就总结出了这些知识,因为套路和模板相对比较多一点,所以之后的题目看起来也会相对轻松一些,

拓扑排序:

内容看了也有5,6道题感悟无非就是找到入度和出度为0分别为0的点,该图也不能够有环,在基础题目上也仅仅就是模板(很多题目也依靠队列实现)例如:P4017 最大食物链计数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

 这周的话多看一些拓扑排序的内容,然后将表格填好,专业课结课的比较多,所以在ACM方面确实投入的精力比之前要小一些,考试结束之后会更加精进的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

钟一淼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值