【数据结构1-3】集合

news2024/11/19 5:36:19

有时候,我们并不关心数据之间的前后关系,也不关心数据的层次关系。一些确定元素只是单纯的聚集在一起,这样的元素聚集体被称为集合。

当希望知道某个数据是否存在一个集合中,或者两个元素是否在同一个集合中时,就需要使用一些集合数据结构来维护集合元素之间的关系。

常见的集合分为并查集,哈希表,STL中的set容器和map容器。

 一、【P1536】村村通(并查集)

标准的并查集模板题,并查集一般具有如下功能。

  1. 动态连边,删边
  2. 动态维护边权,点权
  3. 查询、修改链上的信息(最值,总和等)
  4. 随意指定原树的根(即换根)
  5. 合并两棵树、分离一棵树
  6. 动态维护连通性

 总之,并查集最重要的功能是维护一个集合结构。

AC代码:

 init函数的功能是初始化指定数量的集合,find函数的功能是找到某个节点的父节点,isSame函数的功能是判断两个节点是否属于同一个集合,join函数的功能是将两个节点关联起来。

建立好每个节点的连接关系以后,重新遍历所有节点,默认第一条路径上的第一个点为根节点,所有与根节点不属于同一并查集的节点都视为不可到达。

#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>

using namespace std;
const int INF = 0x7fffffff / 4; //若直接为INT_MAX,则会发生溢出

const int N = 1005;
int pre[N] = { 0 }; //前驱节点
int Rank[N] = { 0 }; //树的高度

void init(int n)
{
	for (int i = 1; i <= n; i++)
	{
		pre[i] = i;
		Rank[i] = 1;
	}
}

int find(int x)
{
	if (pre[x] == x) //找到集合的代表元素
		return x;
	return pre[x] = find(pre[x]);
}

bool isSame(int x, int y)
{
	return find(x) == find(y);
}

bool join(int x,int y)
{
	x = find(x);
	y = find(y);
	if (x == y) //两者已经在一个集合里面了
		return false;
	if (Rank[x] > Rank[y])
		pre[y] = x;
	else if (Rank[x] == Rank[y])
	{
		Rank[x]++;
		pre[y] = x;
	}
	else if (Rank[x] < Rank[y])
	{
		pre[x] = y;
	}
	return true;
}

int main()
{
	while (1)
	{
		int n, m;
		cin >> n;
		if (n == 0) return 0;
		cin >> m;
		if (m == 0)
		{
			cout << n - 1 << endl;
			continue;
		}	
		init(n); //初始化

		int gen, ye;
		cin >> gen >> ye;
		join(gen, ye);
		for (int i = 2; i <= m; i++)
		{
			int a1, a2;
			cin >> a1 >> a2;
			join(a1, a2);
		}
		int cnt = 0;
		for (int i = 1; i <= n; i++)
		{
			if (pre[i] == i && Rank[i] == 1)
			{
				join(i, gen);
				cnt++;
			}
			else if (!isSame(gen, i))
			{
				join(gen, i);
				cnt++;
			}
		}
		cout << cnt << endl;
	}
	
}


 二、【P3370】字符串哈希(hash)

 Hash就是一个像函数的东西,你放进去一个值,它给你输出来一个值。输出的值就是Hash值。一般Hash值会比原来的值更好储存(更小)或比较。

字符串hash就是把字符串转换成一个整数的函数,且要尽量不同字符串对应不同的哈希值。

字符串哈希的主要思路是选取恰当的进制,可以把字符串中的字符看成一个大数字中的每一位数字,不过比较字符串和比较大数字的复杂度并没有什么区别(高精数的比较也是O(n)的),但只要把它对一个数取模,然后认为取模后的结果相等原数就相等,那么就可以在一定的错误率的基础上以O(1)复杂度进行判断了。

1. 进制的选择:

首先不要把任意字符对应到数字0,假如把a对应到数字0,那么将不能只从Hash结果上区分ab和b(虽然可以额外判断字符串长度,但不把任意字符对应到数字0更加省事且没有任何副作用),一般而言,把a-z对应到数字1-26比较合适。

关于进制的选择实际上非常自由,大于所有字符对应的数字的最大值,不要含有模数的质因子(那还模什么),比如一个字符集是a到z的题目,选择27、233、19260817 都是可以的。

2. 模数的选择:

绝大多数情况下,不要选择一个10^9级别的数,因为这样随机数据都会有hash冲突,根据生日悖论,随便找上​约10^5个串就有大概率出现至少一对Hash 值相等的串。

最稳妥的办法是选择两个10^9级别的质数,只有模这两个数都相等才判断相等,但常数略大,代码相对难写,目前暂时没有办法卡掉这种写法(除了卡时间让它超时)。

如果能找出一个10^{18}级别的质数(Miller-Rabin),也是相对靠谱的办法。

 3. 常用的字符串hash分为以下几类:

  • 自然溢出hash:直接使用unsigned long long,不手动进行取模,溢出时会自动对2^{64}进行取模。这种方法虽然简单,但是可能会被卡数据。
  • 单模数hash:选择一个10^{18}级别的质数作为模数,那么理论上数据量超过10^9个才会出现哈希冲突,是相对安全的写法。
  • 双模数hash:选择两个10^9级别的质数作为模数,求两个哈希值,如果两个hash值都相等才能判断两个字符串相等。

AC代码(单模数hash):

#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include <vector>
#include <map>
#include <cstring>
#include <queue>

using namespace std;

typedef unsigned long long ull;
ull base = 131; //进制
ull a[10005]; //用于存储字符串hash
int prime = 233317; //强化hash
ull mod = 212370440130137957ll; //10^18大素数

ull HASH(string s)
{
	ull ans = 0;
	for (int i = 0; i < s.length(); i++)
		ans = (ans * base + (ull)s[i] % mod + prime);
	return ans;
}

int main()
{
	int n;	cin >> n;
	int ans = 0;
	for (int i = 1; i <= n; i++)
	{
		string s;
		cin >> s;
		a[i] = HASH(s);
	}
	sort(a + 1, a + n + 1);
	for (int i = 1; i < n; i++)
	{
		if (a[i] != a[i + 1])
			ans++;
	}
	cout << ans + 1;
}

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

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

相关文章

JVM系列——对象管理

JVM对象分布 对象头 第一类是用于存储对象自身的运行时数据&#xff0c;如哈希码&#xff08;HashCode&#xff09;、GC 分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳等 另外一部分是类型指针&#xff0c;即对象指向它的类型元数据的指针&#xff0c;Java 虚…

敲黑板啦!CSGO游戏搬砖项目操作注意事项

CSGO游戏搬砖项目怎么赚钱的&#xff0c;利润在哪&#xff1f; 1.两个平台之间币种不一样&#xff0c;就存在一个汇率差&#xff0c;两平台装备价格也不一样&#xff0c;汇率差-价格差利润。 CSGO游戏搬砖项目具体有哪些操作步骤&#xff1f; 1、准备一台电脑&#xff0c;配置…

Git学习,基础,安装,配置,笔记总结

Git安装与常用命令 本教程里的git命令例子都是在Git Bash中演示的,会用到一些基本的linux命令,在此为大家提前列举: ls/ll 查看当前目录 cat 查看文件内容 touch 创建文件 vi vi编辑器(使用vi编辑器是为了方便展示效果,学员可以记事本、editPlus、notPad++等其它编 辑…

C#使用OpenCvSharp4库读取电脑摄像头数据并实时显示

一、OpenCvSharp4库 OpenCvSharp4库是一个基于.Net封装的OpenCV库&#xff0c;Github源代码地址为&#xff1a;https://github.com/shimat/opencvsharp&#xff0c;里面有关于Windows下安装OpenCvSharp4库的描述&#xff0c;如下图所示&#xff1a; 二、C#使用OpenCvSharp4库…

React 组件生命周期-概述、生命周期钩子函数 - 挂载时、生命周期钩子函数 - 更新时、生命周期钩子函数 - 卸载时

React 组件生命周期-概述 学习目标&#xff1a; 能够说出组件的生命周期一共几个阶段 组件的生命周期是指组件从被创建到挂在到页面中运行&#xff0c;在到组件不用时卸载组件 注意&#xff1a;只有类组件才有生命周期&#xff0c;函数组件没有生命周期(类组件需要实例化&…

监听项目中指定属性数据,点击或模块显示时

当项目中&#xff0c;需要获取某个页面上、某个标签上、有指定自定义属性时&#xff0c;需要在点击该元素时进行公共逻辑处理&#xff0c;或该元素在显示的时候进行逻辑处理&#xff0c;这时可以定义一个公共的方法&#xff0c;在每个页面引用&#xff0c;并写入数据即可 &…

Win11系统连接带HDMI接口的显示器后,电脑没有声音如何调试

解决这个问题的方法很简单&#xff0c;没有那么复杂。之所以使用HDMI接口连接了显示器后没声音&#xff0c;原因就是HDMI接口是包含音频视频两种信号的接口。当电脑的HDMI接口被使用时&#xff0c;系统就会默认从HDMI设备输出声音信号了&#xff0c;而此时如果HDMI设备没有声音…

基本控件(二)QMainWindow主窗口相关 以及 手写控件的方法 (按F2)

探究过程 先创建个QMainWindow项目。 鼠标点击选中QMainWindow之后按F2&#xff0c;就会进入其最一开始的定义的头文件中。 来到qmainwindow.h头文件中&#xff0c;可以清楚看到这些继承关系&#xff1a; 同样的操作&#xff0c;来到QWidget的定义之处&#xff1a; UI设计界面…

操作符详解(下)

目录 下标访问[ ]、函数调用() [ ] 下标引用操作符 函数调用操作符 结构成员访问操作符 结构体成员的直接访问 操作符的属性&#xff1a;优先级、结合性 优先级 结合性 整型提升 算术转换 下标访问[ ]、函数调用() [ ] 下标引用操作符 操作数&#xff1a;一个数组…

Matlab处理excel数据

我们新建个excel文档&#xff0c;用Matlab读取里面的内容&#xff0c;计算和判断里面的计算结果是否正确&#xff0c;并打印到另一个文档当中。 新建文档 新建输入文档&#xff0c;文件名TestExcel 编写脚本 [num,txt] xlsread(TestExcel.xlsx); SNcode num(:,1);%从序号中…

github连不上

github连不上 错误提示解决方案steam 采用Hosts加速 错误提示 fatal: unable to access ‘https://github.com/Ada-design/qianduan.git/’: Failed to connect to github.com port 443 after 21073 ms: Couldn’t connect to server 解决方案 下载steam https://steampp.ne…

爬虫基础-前端基础

Html是骨骼、css是皮肤、js是肌肉&#xff0c;三者之间的关系可以简单理解为m(html)-v(css)-c(js) 浏览器的加载过程 构建dom树 子资源加载-加载外部的css、图片、js等外部资源 样式渲染-css执行 DOM树 ajax、json、xml AJAX 是一种在无需重新加载整个网页的情况下&#xf…

【CANoe使用大全】——Logging窗口

&#x1f64b;‍♂️【CANoe使用大全】系列&#x1f481;‍♂️点击跳转 文章目录 1.概述2.Logging窗口打开方式3.创建Logging4.配置4.1. 命名4.2.格式选择4.3. 路径选择与命名4.3.1.Logging文件命名_自定义4.3.2.Logging文件命名_系统内选择 5.Logging触发方式5.1 Logging模块…

MATLAB - 仿真单摆的周期性摆动

系列文章目录 前言 本例演示如何使用 Symbolic Math Toolbox™ 模拟单摆的运动。推导摆的运动方程&#xff0c;然后对小角度进行分析求解&#xff0c;对任意角度进行数值求解。 一、步骤 1&#xff1a;推导运动方程 摆是一个遵循微分方程的简单机械系统。摆最初静止在垂直位置…

怎样做好Code Review

Code Review方案 定义 Code Review代码评审是指在软件开发过程中&#xff0c;通过对源代码进行系统性检查的过程。通常的目的是查找各种缺陷&#xff0c;包括代码缺陷、功能实现问题、编码合理性、性能优化等&#xff1b;保证软件总体质量和提高开发者自身水平 code review …

【C语言刷题系列】计算整数的二进制位中1的个数 (三种方式)

文章目录 一、文章简介 1.取模 配合 整除 的方式 2.按位与 配合 右移 的方式 3.按位与 的方式 一、文章简介 本文所属专栏C语言刷题_倔强的石头106的博客-CSDN博客 注&#xff1a;如果没有特别说明&#xff0c;本文所提及的整数为有符号整型&#xff0c;即 int 类型 本文…

452. 用最少数量的箭引爆气球 - 力扣(LeetCode)

题目描述 有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points &#xff0c;其中points[i] [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。 一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标 …

JVM 笔记

JVM HotSpot Java二进制字节码的运行环境 好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;具有垃圾回收功能数组下标越界检查多态&#xff08;虚方法表&#xff09; JVM组成 类加载子系统&#xff08;Java代码转换为字节码&#xff09;运行时数据…

MongoDB实战

1.MongoDB介绍 1.1 什么是MongoDB MongoDB是一个文档数据库&#xff08;以JSON 为数据模型&#xff09;&#xff0c;由C语言编写&#xff0c;旨在为WEB应用提供可扩展的高性能数据存储解决方案。 文档来自于"JSON Document"&#xff0c;并非我们一般理解的 PDF&…

gdb 调试 - 在vscode图形化展示在远程的gdb debug过程

前言 本地机器的操作系统是windows&#xff0c;远程机器的操作系统是linux&#xff0c;开发在远程机器完成&#xff0c;本地只能通过ssh登录到远程。现在目的是要在本地进行图形化展示在远程的gdb debug过程。&#xff08;注意这并不是gdb remote &#xff01;&#xff01;&am…