并查集OJ做题报告

并查集

洛谷P3367

模板并查集

以后要注意的:

  1. scanf函数括号里面要写好,先双引号" " ,再用逗号,将输入内容和变量分开

洛谷P1525

关押罪犯

学到了:

  1. sort函数的第三个参数,该参数是一比较参数,决定排序完数据是升序还是降序
cpp 复制代码
bool cmp(int a,int b){
	return a>b;//可以理解为当a>b时把a放在b前面,就是升序
	//return a<b;可以理解为当a<b时把a放在b前面,就是降序
}
  1. 结构体数组排序
    1. 先定义结构体
cpp 复制代码
struct node{
	int a,b,c;
}x[10];
  1. 输入数据
cpp 复制代码
for(int i=1;i<=m;i++){
		scanf("%d %d %d",&x[i].a,&x[i].b,&x[i].c);
		} 

3.设立比较条件

  • 一级排序(将c从大到小排序)
cpp 复制代码
bool cmp(node i,node j){
	return i.c>j.c;
}
  • 二级排序(c相等的情况下,按照b大小来从小到大排序)
cpp 复制代码
bool cmp(node i,node j){
	if(i.c==j.c){
		return i.b>j.b;
	}else{
		return i.c>j.c;
	}
}

以后要注意的:

  • 种类并查集就是找出有哪些不同种类(不同集合)
  • 在一数组上划分不同的状态(比如i为正状态,则i+n为反状态,两者不共存)
  • 当题目要求分开x和y时,我们就需要合并x和y的反状态,y和x的反状态
  • 判断是否已经区分就是查看是否在一个集合(普通并查集),找父节点

洛谷CF776D

CF776D The Door Problem

思路:

怎么想到用并查集的?

  1. 我们已经得知每盏灯的初始状态和哪两个开关控制它。

  2. 首先分类讨论:

    • 如果最开始这盏灯是开着的,那么这两个开关应该做出同样的操作,即要么全按,要么全不按。

    • 如果最开始这盏灯是关着的,那么这两个开关应该做出不同的操作,即一个按一个不按。

    • 转化一个思路,就变成了有 m 个数,其中有 n 个关系,有些关系是两个数要一样,有些关系是两个数要不一样,问是否合理。

  3. 维护开与关的关系,我们想到了并查集。

该题目最重要的一句话:每扇门恰好被两个开关控制

而每扇门只有两个状态:

  1. 0状态,房间门是锁着的
  2. 1状态,房间门的开着的

依题意现在每一扇门对应两个钥匙,设门为开 的状态为(u,v),设门为关 的状态为(u+m,v+m)且一共有m个开关数,则:

  • 对于开着的门:

    合并(u,v)(u+m,v+m)

    • 同种状态钥匙开一遍才能保持门是"开"的状态
  • 对于关着的门:

    合并(u,v+m),(u+m,v)

    • 不同种状态的钥匙开一遍才能保证门是关着的

当合并完之后,我们只需要遍历所有开关数 i ,当发现ii+m在同一集合,则输出 "NO",因为一把钥匙只能有使用或不使用的状态.所以如果ii+m在一个并查集内,这是不合法的

这一流程用并查集文字意思就是:

  • 遍历每一个门的时候赋予每一个开关开或不开的状态,当有一个开关矛盾了(就是开和不开同时需要满足),则依题意输出 "NO"。

这里的输入流程比较麻烦:

  1. 输入房间数和开关数
  2. 输入房间状态(基于房间数)
  3. 输入控制房间数量
  4. 输入钥匙控制房间的编号(基于第3点)
    • 这里要用一个结构体数组来存数据,数组下标是房间号,结构体里面是能控制对应房间号的两个钥匙
cpp 复制代码
struct key{
	int a,b;
}x[200005];
for(int i=1;i<=m;i++){		//i是开关编号 
		int c;
		scanf("%d",&c);			//控制的房间数量 
		for(int j=1;j<=c;j++){
			int d;
			scanf("%d",&d);		//被控制的房间编号
			if(x[d].a==0){
				x[d].a=i; 		//房间编号d由2个开关中的i开关控制 
			}else{
				x[d].b=i;
			}
		}
	}
}

以后要注意的:

  1. 处理并查集时始终用一个函数来合并集合,避免直接修改父节点数组(或者修改完父节点数组后再次重新查找父节点),因为这会破坏路径压缩,导致循环引用或造成错误的集合关系,破坏了并查集结构
相关推荐
6Hzlia5 分钟前
【Hot 100 刷题计划】 LeetCode 287. 寻找重复数 | C++ 数组判环 (快慢指针终极解法)
c++·算法·leetcode
MegaDataFlowers6 分钟前
26.删除有序数组中的重复项
算法
故事和你911 小时前
洛谷-数据结构1-4-图的基本应用2
开发语言·数据结构·算法·深度优先·动态规划·图论
吴可可1232 小时前
C#合并首尾相连多段线实战
算法·c#
KMDxiaozuanfeng2 小时前
卡梅德生物技术快报|SPR 技术应用|基于 SPR 亲和力的中药活性成分筛选系统实现与数据分析
科技·算法·面试·考试
꧁细听勿语情꧂3 小时前
数据结构概念和算法、时间复杂度、空间复杂度引入
c语言·开发语言·数据结构·算法
Felven3 小时前
B. The 67th 6-7 Integer Problem
数据结构·算法
玉树临风ives3 小时前
atcoder ABC 454 题解
算法·深度优先·图论
钮钴禄·爱因斯晨3 小时前
聚焦操作系统中的PV操作
数据库·算法·系统架构·c#
云泽8083 小时前
笔试算法 - 双指针篇(一):移动零、复写零、快乐数与盛水容器
c++·算法