并查集 How many tables(hdu 1213) How many answers are wrong(hdu 3038)

news2024/11/14 14:45:05

目录

前言

并查集

   并查集的初始化

   并查集的合并

   并查集合并的优化,路径压缩

How many tables(hdu 1213)

   问题描述

   输入

   输出

问题分析

代码

带权并查集

How many answers are wrong(hdu 3038)

   问题描述

   输入

   输出

问题分析

代码


前言

        感觉并查集总共有两个应用,一是解决有关群的问题,二是利用并查集构造一个只有叶子的高效权值树。比方说a和b是朋友b和c是朋友,那么a,b,c这三个人在并查集中就属于同一个集合,如果经过路径压缩后a,b,c三个人的集合就会指向一处

并查集

   并查集的初始化

        最开始初始化并查集时,每个元素的都代表一个独立的集,注意是独立的集,集合间不存在包含和被包含关系,如果是用数组实现我们一般习惯set[i] = i,来表示,也就是元素i的集合被初始化为集合i,这里虽然集合和元素名字相同,但代表的是不同的涵义

   并查集的合并

        并查集的合并操作有点像链表的链接,每个节点都有一个data域和指向其所属集合的指针域,比方说如果要把1集合合并到2集合,那么只需要将1集合的指针域指向2集合即可,再让2集合合并到3集合重复操作,经过一系列操作我们就会发现我们得到了一个1,2,3,4,5的链表。

        感觉有哪里不对吧,我们使用并查集是为了使得算法更加高效,但这样操作好像还不如直接使用一个数组呢,其实这和我们的连接方式有关,注意到每次我们链接的时候都是将大的集合链接到小的集合之上,导致我们连接的结果形成了一棵单支树,但如果把小集合合并到大集合上那么就会实现一颗比较好的多支树,如何避免变成单只树呢?

   并查集合并的优化,路径压缩

        前边说到如果都将大集合合并到小集合之上那么会使得形成的树深度非常深,那么不然就在合并的时候优化一下不就行了呗,不妨在合并操作的时候设计一个变量记录合并之后集合的深度,之后每一次合并的时候都判断一下,保证将小集合合并到大集合中。

        但其实上述还可以优化,并查集主要用处就是给定一个元素,可以快速找到他所处的集合,那么如果并查集所形成的树只有叶子节点那么这不就极大提高了算法效率吗,所以又想出了路径压缩的算法。主要算法思想就是在搜索元素所处的集合的同时将路径上的元素全部直接与集合相连,设计递归的思想,需要仔细理解。

int find_set(int x) {
	if (x != s[x]) s[x] = find_set(s[x]);
	return s[x];   //if(x==s[x]) return s[x];   //效果相同
}

        普通的并查集主要解决分类的问题,下面我们来看一道题。

How many tables(hdu 1213)

hdu 1213

   问题描述

        有一群人去聚会,好朋友之间会坐一桌,规定朋友的朋友也是朋友,问最少需要几桌。

   输入

        第一行输入一个整数T,代表有T个测试,对于每个测试第一行输入两个整数N,M,N代表参会人的编号,之后的M行中每行输入两个整数A,B代表编号A,B两个人为好朋友。

   输出

        对于每个测试输出一行做为答案。

问题分析

        这是一个恒明显的并查集的应用,涉及到分类的问题。

代码

#include<iostream>
using namespace std;
const int E = 1050;

int s[E+1];
int height[E+1];

void init_set() {
	for (int i = 1; i <= E; i++) {
		s[i] = i;
	}
}

int find_set(int x) {
	if (x != s[x]) s[x] = find_set(s[x]);
	return s[x];   //if(x==s[x]) return s[x];   //效果相同
}
/*height[i] = 0;
void merge_set(int a, int b) {
	int roota = find_set(a), rootb = find_set(b);
	if (height[roota] == height[rootb]) {
		s[roota] = rootb; //把a集合接到b上
		height[rootb] += 1;
	}
	else {
		if (height[roota] > height[rootb]) s[rootb] = roota;
		if (height[roota] < height[rootb]) s[roota] = rootb;
	}
}*/

void merge_set(int a, int b) {
	int roota = find_set(a), rootb = find_set(b);
	if (roota != rootb) {
		s[roota] = rootb;
	}
}

int main() {
	int T;
	cin >> T;
	while (T--) {
		init_set();
		int N, M,A,B;
		cin >> N >> M;
		for (int i = 1; i <= M; i++) {
			cin >> A >> B;
			merge_set(A, B);
		}
		int ans = 0;
		for (int i = 1; i <= N; i++) {
			if (s[i] == i) ans++;
		}
		cout << ans << endl;
	}
}

        下面我们来介绍并查集的另一个应用——带权并查集

带权并查集

        想象一个场景,我需要求一个地方到达目的地的距离,但我只知道到途径的几个地方的距离,如何快速得到想要的答案?再回顾我们所说的并查集,它可以很快的查询到节点到根节点,也就是可以迅速查询到所属的集合,那么根据这个特性,给并查集加上权值,这个权值可以是距离,或者是其他的关系,那么就可以迅速查到与根节点的距离(或其他关系)

        这样说可能还是不大形象,下面我们更具一道具体的例题来理解。

How many answers are wrong(hdu 3038)

hdu 3038

   问题描述

        给定几个区间和,试判断对于某个区间和,在前面正确的区间和的基础上,这个区间和是否为真,输出所有假区间和的个数。

   输入

        有多个测试,对于每个测试,第一行输入两个整数n,m,代表有n个整数m组数据,之后的m行中每行输入三个整数a,b,v,代表左闭右闭区间【a,b】区间和为v

   输出

        对于每个测试,输出发生冲突区间和的个数。

问题分析

        本题的区间和其实可以抽象为距离,为了便于理解,我们就抽象为距离哈。

        前面说到使用并查集可以快速找到当前节点与根节点的距离,那么能不能利用这个特性解决这个问题呢,要判断这个节点是否与前面的节点发生冲突,如果前面的节点我都改为到根节点的距离那么想利用前面的节点推算给定区间和只需要这样【a,b】=【a,root】-(b,root】即可,但是会发现这几个区间的表示形式不对,那么我不妨都改为左开右闭区间即:

                                                  [a+1,b] = (a,b】= (a,c】- (b,c】

        值得注意的是每次加入节点的时候还需要更新节点的权值为它到根节点的距离

void init_set() {
	for (int i = 1; i <= E; i++) {
		s[i] = i;
		d[i] = 0;
	}
}

int find_set(int x) {
	if (x != s[x]) {
		int t = s[x];
		s[x] = find_set(s[x]);
		d[x] += d[t];  //注意这里是递归式,到了根节点才会开始累加
	}
	return s[x];   //if(x==s[x]) return s[x];   //效果相同
}

        本题最后的要点就是在两个集合合并的时候如何处理两个根节点之间的权值,我们不如用小学数学知识算一下

  • (a,b]                          距离v
  • (b,rootb]                      距离d[b]
  • (a,roota]                      距离d[a]
  • 要求(roota,rootb]        距离d[roota]
  • 因为                   (a,roota] - (b,roota] = (a,b] 
  • 那么                   (b,roota] = (a,roota] - (a,b]
  • 那么                   (b,rootb] - (roota,rootb] = (b,roota]
  • 则                    (roota,rootb] = (b,rootb] - (b,roota]
  • 即                      (roota,rootb] = (b,rootb] - (a,roota] + (a,b]
  •                       d[roota] = d[b] -d[a] + v

        怎么样,很神奇吧,应该没有绕晕吧。。。。。,

那么接下来就可以开始编代码了

代码

#include<iostream>
using namespace std;
const int E = 200010;

int s[E + 1];
int d[E + 1];  //d[i]代表区间(i,root]的区间和
int ans = 0;

void init_set() {
	for (int i = 1; i <= E; i++) {
		s[i] = i;
		d[i] = 0;  //初始化距离为0
	}
}

int find_set(int x) {
	if (x != s[x]) {
		int t = s[x];
		s[x] = find_set(s[x]);
		d[x] += d[t];  //注意这里是递归式,到了根节点才会开始累加
	}
	return s[x];   //if(x==s[x]) return s[x];   //效果相同
}

void merge_set(int a, int b, int v) {
	int roota = find_set(a), rootb = find_set(b);
	if (roota == rootb) {
		if ((d[a] - d[b]) != v) ans++;
	}
	else {
		s[roota] = s[rootb]; //将a所在的树接到b上
		d[roota] = d[b] - d[a] + v;  //更新a的根节点到b的根节点之间的距离
	}
}

int main() {
	int n, m,a,b,v;
	while (cin >> n >> m) {
		init_set();  //千万不要忘记初始化了,错了几次了,真服了我自己
		while (m--) {
			cin >> a >> b >> v;
			a--;
			merge_set(a, b, v);
		}
		cout << ans << endl;
	}
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2237769.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaScript day01 笔记

一、引入方式 JavaScript 程序不能独立运行&#xff0c;它需要被嵌入 HTML 中&#xff0c;然后浏览器才能执行 JavaScript 代码。通过 script 标签将 JavaScript 代码引入到 HTML 中 1️⃣内部 通过 script 标签包裹 JavaScript 代码&#xff08;一般就写在</script>的…

Notepad++ 最新官网中文版在线下载 附文本编辑器安装与基础使用教程

Notepad &#xff08;记事本&#xff09;是一个简单的文本编辑器&#xff0c;预装在所有版本的 Microsoft Windows 操作系统中。它的主要功能是创建、编辑和存储纯文本文件&#xff0c;通常以 .txt 格式保存。Notepad 的设计旨在提供一个轻量级的文本处理工具&#xff0c;适合快…

使用C语言进行信号处理:从理论到实践的全面指南

1. 引言 在现代操作系统中&#xff0c;信号是一种进程间通信机制&#xff0c;它允许操作系统或其他进程向一个进程发送消息。信号可以用来通知进程发生了一些重要事件&#xff0c;如用户请求终止进程、硬件异常、定时器超时等。掌握信号处理技术对于开发健壮、高效的系统程序至…

大数据入门-什么是HBase

目录 一、概念 二、架构 1.Client 2.Zookeeper 3.HMaster 4.HRegionServer 三、特性 1.数据存储庞大 2.支持随机读写 3.轻松融入生态 4.数据强一致性 5.性能足够高效 四、适用场景 五、其他事宜 1.权益备注 2.支持博主 大数据入门系列文章 这里简单介绍的HBas…

【笔记】自动驾驶预测与决策规划_Part6_不确定性感知的决策过程

文章目录 0. 前言1. 部分观测的马尔可夫决策过程1.1 POMDP的思想以及与MDP的联系1.1.1 MDP的过程回顾1.1.2 POMDP定义1.1.3 与MDP的联系及区别POMDP 视角MDP 视角决策次数对最优解的影响 1.2 POMDP的3种常规解法1.2.1 连续状态的“Belief MDP”方法1. 信念状态的定义2. Belief …

Vue2中使用firefox的pdfjs进行文件文件流预览

文章目录 1.使用场景2. 使用方式1. npm 包下载,[点击查看](https://www.npmjs.com/package/pdfjs-dist)2. 官网下载1. 放到public文件夹下面2. 官网下载地址[点我,进入官网](https://github.com/mozilla/pdf.js/tags?afterv3.3.122) 3. 代码演示4. 图片预览5. 如果遇到跨域或者…

MFC图形函数学习06——画椭圆弧线函数

绘制椭圆弧线函数是MFC基本绘图函数&#xff0c;这个函数需要的参数比较多&#xff0c;共四对坐标点。前两对坐标点确定椭圆的位置与大小&#xff0c;后两对坐标确定椭圆弧线的起点与终点。 一、绘制椭圆弧线函数 原型&#xff1a;BOOL Arc(int x1,int y1,int x2,int y2…

新版 idea 编写 idea 插件时,启动出现 ClassNotFound

IntelliJ IDEA 2024.1.6 (Ultimate Edition) Build #IU-241.19072.14, built on August 8, 2024 Licensed to Sophia Tout Subscription is active until June 29, 2025. For educational use only. Runtime version: 17.0.111-b1207.30 amd64 Kotlin: 241.19072.14-IJ 新版本…

信息安全工程师(83)Windows操作系统安全分析与防护

一、Windows操作系统安全分析 系统漏洞&#xff1a; Windows操作系统由于其复杂性和广泛使用&#xff0c;可能存在一些已知或未知的漏洞。这些漏洞可能会被黑客利用&#xff0c;进行恶意攻击。微软会定期发布系统更新和补丁&#xff0c;以修复这些漏洞&#xff0c;提高系统的安…

【嵌入式开发——ARM】1ARM架构

嵌入式领域&#xff0c;使用ARM架构的芯片公司可不占少数吧&#xff0c;intel的x86架构主要占据PC、服务器市场&#xff0c;ARM架构主要占据移动市场。x86架构和ARM架构不同的主要原因&#xff0c;是背后使用的计算机指令集不同。计算机有自己的语言系统&#xff08;汇编&#…

31-自定义地图:分层地图

利用自定义地图中的级别&#xff0c;可以让多个人同时在一张地图上工作。它还允许您在仿真过程中使用Python API在地图上加载和卸载层&#xff0c;就像分层的CARLA地图一样(layered CARLA maps)。 本指南将解释如何添加新级别&#xff0c;如何向级别添加资产&#xff0c;以…

操作系统-磁盘

文章目录 磁盘的结构一、磁盘的物理结构二、磁盘的逻辑结构 磁盘的调度算法磁盘时间算法先来先服务&#xff08;FCFS - First-Come, First-Served&#xff09;最短寻道时间优先&#xff08;SSTF - Shortest Seek Time First&#xff09;扫描算法&#xff08;SCAN&#xff0c;也…

【Linux】【信号操作】汇总整理

信号&#xff08;Signals&#xff09;是操作系统中用于通知进程发生特定事件的一种机制。信号可以由软件或硬件触发&#xff0c;并且可以被进程捕获和处理。以下是信号的相关概念、常见信号列表、信号处理以及相关API的汇总整理。 信号概述 信号是操作系统向进程发出的通知&am…

必备的计算机软件专业资料汇总,包括:计算机专业实习报告,计算机毕业设计成品(含源码和论文1900套)

大学期间必备的计算机软件专业资料汇总&#xff0c;包括&#xff1a;计算机专业实习报告&#xff08;58篇&#xff09;、计算机毕业设计成品&#xff08;含源码和论文&#xff0c;1900多套&#xff0c;包括C语言/PHP/VB/java/JSP/Andorid/Python/微信小程序等&#xff09;、HTM…

业务模块部署

一、部署前端 1.1 window部署 下载业务模块前端包。 &#xff08;此包为耐威迪公司发布&#xff0c;请联系耐威迪客服或售后获得&#xff09; 包名为&#xff1a;业务-xxxx-business &#xff08;注&#xff1a;xxxx为发布版本号&#xff09; 此文件部署位置为&#xff1a;……

使用kalibr_calibration标定相机(realsense)和imu(h7min)

vslam-evaluation/VINS/Installation documentation/4.IMU和相机联合标定kalibr_calibration.md at master DroidAITech/vslam-evaluation GitHub 目录 1.kalibr安装 1.1安装依赖项 1.2创建工作空间 1.3下载kalibr并编译 1.4设置环境变量 2.准备标定板 3.配置驱动和打…

Java | Leetcode Java题解之第551题学生出勤记录I

题目&#xff1a; 题解&#xff1a; class Solution {public boolean checkRecord(String s) {int absents 0, lates 0;int n s.length();for (int i 0; i < n; i) {char c s.charAt(i);if (c A) {absents;if (absents > 2) {return false;}}if (c L) {lates;if …

MATLAB课程:AI工具辅助编程——MATLAB+LLMs

给出一些可能有用的方法辅助大家写代码。 方法一&#xff1a;MATLAB软件LLM (不太懂配置的同学们为了省事可以主要用这个方法) 方法一特别针对本门MATLAB教学课程&#xff0c;给出一种辅助ai工具的操作指南。MATLAB中可以安装MatGPT插件&#xff0c;该插件通过调用ChatGPT的API…

腾讯混元3D-1.0:文本到三维和图像到三维生成的统一框架

虽然三维生成模型极大地改进了艺术家的工作流程&#xff0c;但现有的三维生成扩散模型存在生成速度慢、泛化能力差的问题。 为了解决这个问题&#xff0c;我们提出了一种名为 "Hunyuan3D-1.0 "的两阶段方法&#xff0c;包括精简版和标准版&#xff0c;均支持文本和图…

现代Web开发:Vue 3 组件化开发实战

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 现代Web开发&#xff1a;Vue 3 组件化开发实战 现代Web开发&#xff1a;Vue 3 组件化开发实战 现代Web开发&#xff1a;Vue 3 组…