【并查集专题】【蓝桥杯备考训练】:网络分析、奶酪、合并集合、连通块中点的数量、格子游戏【已更新完成】

目录

1、网络分析(第十一届蓝桥杯省赛第一场C++ A组/B组)

2、奶酪(NOIP2017提高组)

3、合并集合(模板)

4、连通块中点的数量(模板)

5、格子游戏(《信息学奥赛一本通》)


1、网络分析(第十一届蓝桥杯省赛第一场C++ A组/B组)

小明正在做一个网络实验。

他设置了 n 台电脑,称为节点,用于收发和存储数据。

初始时,所有节点都是独立的,不存在任何连接。

小明可以通过网线将两个节点连接起来,连接后两个节点就可以互相通信了。

两个节点如果存在网线连接,称为相邻。

小明有时会测试当时的网络,他会在某个节点发送一条信息,信息会发送到每个相邻的节点,之后这些节点又会转发到自己相邻的节点,直到所有直接或间接相邻的节点都收到了信息。

所有发送和接收的节点都会将信息存储下来。

一条信息只存储一次。

给出小明连接和测试的过程,请计算出每个节点存储信息的大小。

输入格式

输入的第一行包含两个整数 n,m,分别表示节点数量和操作数量。

节点从 1 至 n 编号。

接下来 m 行,每行三个整数,表示一个操作。

  • 如果操作为 1 a b,表示将节点 a 和节点 b 通过网线连接起来。当 a = b 时,表示连接了一个自环,对网络没有实质影响。
  • 如果操作为 2 p t,表示在节点 p 上发送一条大小为 t 的信息。
输出格式

输出一行,包含 n 个整数,相邻整数之间用一个空格分割,依次表示进行完上述操作后节点 1 至节点 n 上存储信息的大小。

数据范围

1≤n≤10000
1≤m≤1e5
1≤t≤100

输入样例1:
4 8
1 1 2
2 1 10
2 3 5
1 4 1
2 2 2
1 1 2
1 2 4
2 2 1
输出样例1:
13 13 5 3
思路:

连接的时候创建一个新的根节点,作为祖先(通过创建新节点,可以实现在之后的dfs中不会将之前的信息加到后连接的计算机上

依次执行输入的指令,传达的信息都加到根节点上

dfs,把发送的信息全部累加到根节点上

遍历输出根节点的信息(如果对于节点i,p[i]==i则说明这是个根节点,不然说明这个根节点已经其点的子节点了

代码:
#include<bits/stdc++.h>using namespace std;const int N=2e4+10,M=N<<1;int p[N];int h[M],e[M],ne[M],idx;int add(int a,int b)
{e[idx]=b;//值存到e里(idx是e的编号) ne[idx]=h[a];//d的编号的下一个指向h【a】指向的编号 h[a]=idx++;//h【a】指向b的编号 
}int f[N];//存储信息 int n,m;int find(int x)
{if(x!=p[x])p[x]=find(p[x]);return p[x];
}void merge(int a,int b,int &root)
{a=find(a);b=find(b);if(a!=b){p[a]=p[b]=root;add(root,a);add(root,b);root++;}
}void dfs(int son,int father)
{f[son]+=f[father];for(int i=h[son];i!=-1;i=ne[i]){int j=e[i];dfs(j,son);}
}int main()
{memset(h,-1,sizeof h);cin>>n>>m;for(int i=1;i<=n*2;i++){p[i]=i;}int root=n+1; while(m--){int t,a,b;cin>>t;cin>>a>>b;//cout<<"yes";//cout<<m<<endl;if(t==1){merge(a,b,root);}else{a=find(a);f[a]+=b;}//cout<<m<<endl;}//cout<<"yes1";for(int i=n+1;i<root;i++)if(p[i]==i)dfs(i,0);//把每个根节点的值传递到每个计算机上for(int i=1;i<=n;i++)cout<<f[i]<<" ";return 0;
}
/*4 8
1 1 2
2 1 10
2 3 5
1 4 1
2 2 2
1 1 2
1 2 4
2 2 113 13 5 3*/

2、奶酪(NOIP2017提高组)

现有一块大奶酪,它的高度为 h,它的长度和宽度我们可以认为是无限大的,奶酪中间有许多半径相同的球形空洞。

我们可以在这块奶酪中建立空间坐标系,在坐标系中,奶酪的下表面为 z=0,奶酪的上表面为 z=h。 

现在,奶酪的下表面有一只小老鼠 Jerry,它知道奶酪中所有空洞的球心所在的坐标。

如果两个空洞相切或是相交,则 Jerry 可以从其中一个空洞跑到另一个空洞,特别地,如果一个空洞与下表面相切或是相交,Jerry 则可以从奶酪下表面跑进空洞;如果一个空洞与上表面相切或是相交,Jerry 则可以从空洞跑到奶酪上表面。

位于奶酪下表面的 Jerry 想知道,在不破坏奶酪的情况下,能否利用已有的空洞跑到奶酪的上表面去? 

空间内两点 P1(x1,y1,z1)、P2(x2,y2,z2)的距离公式如下:

输入格式

每个输入文件包含多组数据。  

输入文件的第一行,包含一个正整数 T,代表该输入文件中所含的数据组数。  

接下来是 T组数据,每组数据的格式如下:

第一行包含三个正整数 n,h,和 r,两个数之间以一个空格分开,分别代表奶酪中空洞的数量,奶酪的高度和空洞的半径。  

接下来的 n 行,每行包含三个整数 x、y、z,两个数之间以一个空格分开,表示空洞球心坐标为 (x,y,z)。

输出格式

输出文件包含 T 行,分别对应 T 组数据的答案,如果在第 i 组数据中,Jerry 能从下表面跑到上表面,则输出 Yes,如果不能,则输出 No

数据范围

1≤n≤1000
1≤h,r≤1e9
T≤20
坐标的绝对值不超过1e9

输入样例:
3 
2 4 1 
0 0 1 
0 0 3 
2 5 1 
0 0 1 
0 0 4 
2 5 2 
0 0 2 
2 0 4
输出样例:
Yes
No
Yes
思路:

多源dfs(推荐)

或者并查集

代码:

多源bfs

#include <bits/stdc++.h>
using namespace std;
int t, n, h, r, f[1010];
double x[1010], y[1010], z[1010];inline double dist(double X1, double X2, double Y1, double Y2, double Z1, double Z2) {return sqrt((X1 - X2) * (X1 - X2) + (Y1 - Y2) * (Y1 - Y2) + (Z1 - Z2) * (Z1 - Z2));
}int main() {scanf("%d", &t);while (t--) {scanf("%d%d%d", &n, &h, &r);for (int i = 1; i <= n; i++) scanf("%lf%lf%lf", &x[i], &y[i], &z[i]), f[i] = 0;queue<int> q; bool ok = 0;for (int i = 1; i <= n; i++) if (z[i] <= r) q.push(i), f[i] = 1;while (q.size()) {int p = q.front(); q.pop();if (ok) break;if (z[p] + r >= h) {ok = 1; puts("Yes"); break;}for (int i = 1; i <= n; i++) {if (f[i]) continue;if (dist(x[p], x[i], y[p], y[i], z[p], z[i]) <= 2 * r) {q.push(i), f[i] = 1;if (z[i] + r >= h) {ok = 1; puts("Yes"); break;}}}}if (!ok) puts("No");}return 0;
}

并查集:

#include <bits/stdc++.h>
using namespace std;
int t, n, h, r;
int t1, s1[1010], t2, s2[1010], fa[1010];
pair<long long, pair<long long, long long> > a[1010];int get(int x) {if (fa[x] != x) fa[x] = get(fa[x]);return fa[x];
}
double dist(double X1, double X2, double Y1, double Y2, double Z1, double Z2) {return sqrt(pow(X1 - X2, 2) + pow(Y1 - Y2, 2) + pow(Z1 - Z2, 2));
}int main() {scanf("%d", &t);while (t--) {scanf("%d%d%d", &n, &h, &r); t1 = 0, t2 = 0;for (int i = 1; i <= n; i++) fa[i] = i;for (int i = 1; i <= n; i++) {scanf("%lld%lld%lld", &a[i].second.first, &a[i].second.second, &a[i].first);if (a[i].first + r >= h) s1[++t1] = i;if (a[i].first - r <= 0) s2[++t2] = i;}if (t1 == 0 || t2 == 0) {puts("No"); continue;}for (int i = 1; i <= n; i++)for (int j = i + 1; j <= n; j++) {if (get(i) == get(j)) continue;double d = dist(a[i].second.first, a[j].second.first, a[i].second.second, a[j].second.second, a[i].first, a[j].first);if (d <= 2 * r) fa[get(i)] = get(j);}int b = 0;for (int i = 1; i <= t1; i++) {if (b) break;for (int j = 1; j <= t2; j++)if (get(s1[i]) == get(s2[j])) {puts("Yes"); b = 1; break;}}if (!b) puts("No");}return 0;
}

3、合并集合(模板)

一共有 n 个数,编号是 1∼n,最开始每个数各自在一个集合中。

现在要进行 m 个操作,操作共有两种:

  1. M a b,将编号为 a和 b的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个操作;
  2. Q a b,询问编号为 a 和 b 的两个数是否在同一个集合中;
输入格式

第一行输入整数 n 和 m。

接下来 m 行,每行包含一个操作指令,指令为 M a b 或 Q a b 中的一种。

输出格式

对于每个询问指令 Q a b,都要输出一个结果,如果 a 和 b 在同一集合内,则输出 Yes,否则输出 No

每个结果占一行。

数据范围

1≤n,m≤1e5

输入样例:
4 5
M 1 2
M 3 4
Q 1 2
Q 1 3
Q 3 4
输出样例:
Yes
No
Yes
思路:

写好find函数和merge函数

代码:
#include<bits/stdc++.h>using namespace std;const int N=1e5+5;int n,m;int p[N];int find(int x)
{if(x!=p[x])p[x]=find(p[x]);return p[x];
}void merge(int a,int b)
{p[find(a)]=find(b);//a的祖先添加到b的祖先下面 
}int main()
{cin>>n>>m;for(int i=1;i<=n;i++)p[i]=i;while(m--){char op;int a,b;cin>>op;cin>>a>>b;if(op=='M'){merge(a,b);}else{if(find(a)==find(b))cout<<"Yes"<<endl;else cout<<"No"<<endl; }}//Yes Noreturn 0;
} 

4、连通块中点的数量(模板)

给定一个包含 n 个点(编号为 1∼n)的无向图,初始时图中没有边。

现在要进行 m 个操作,操作共有三种:

  1. C a b,在点 a 和点 b之间连一条边,a 和 b 可能相等;
  2. Q1 a b,询问点 a 和点 b是否在同一个连通块中,a 和 b 可能相等;
  3. Q2 a,询问点 a 所在连通块中点的数量;
输入格式

第一行输入整数 n 和 m。

接下来 m 行,每行包含一个操作指令,指令为 C a bQ1 a b 或 Q2 a 中的一种。

输出格式

对于每个询问指令 Q1 a b,如果 a和 b 在同一个连通块中,则输出 Yes,否则输出 No

对于每个询问指令 Q2 a,输出一个整数表示点 a 所在连通块中点的数量

每个结果占一行。

数据范围

1≤n,m≤1e5

输入样例:
5 5
C 1 2
Q1 1 2
Q2 1
C 2 5
Q2 5
输出样例:
Yes
2
3

思路:

cnt数组统计连通块中点的数量(注意数量全放在祖先节点),合并函数(merge)中进行累加

代码:
#include<bits/stdc++.h>using namespace std;const int N=1e5+10;int n,m;int p[N];
int cnt[N];int find(int x)
{if(x!=p[x])p[x]=find(p[x]);return p[x];
}void merge(int a,int b)
{cnt[find(b)]+=cnt[find(a)];p[find(a)]=find(b);
}int main()
{cin>>n>>m;for(int i=1;i<=n;i++){p[i]=i;cnt[i]=1;}while(m--){char op[5];cin>>op;if(op[0]=='C'){int a,b;cin>>a>>b;if(find(a)==find(b))continue;merge(a,b);}else if(op[1]=='1'){int a,b;cin>>a>>b;if(find(a)==find(b))cout<<"Yes"<<endl;else cout<<"No"<<endl;}else{int t;cin>>t;cout<<cnt[find(t)]<<endl;}}return 0;
}

5、格子游戏(《信息学奥赛一本通》)

Alice和Bob玩了一个古老的游戏:首先画一个 n×n的点阵(下图 n=3 )。

接着,他们两个轮流在相邻的点之间画上红边和蓝边:

1.png

直到围成一个封闭的圈(面积不必为 1)为止,“封圈”的那个人就是赢家。因为棋盘实在是太大了,他们的游戏实在是太长了!

他们甚至在游戏中都不知道谁赢得了游戏。

于是请你写一个程序,帮助他们计算他们是否结束了游戏?

输入格式

输入数据第一行为两个整数 n 和 m。n表示点阵的大小,m 表示一共画了 m 条线。

以后 m 行,每行首先有两个数字 (x,y),代表了画线的起点坐标,接着用空格隔开一个字符,假如字符是 D,则是向下连一条边,如果是 R 就是向右连一条边。

输入数据不会有重复的边且保证正确。

输出格式

输出一行:在第几步的时候结束。

假如 m 步之后也没有结束,则输出一行“draw”。

数据范围

1≤n≤200
1≤m≤24000

输入样例:
3 5
1 1 D
1 1 R
1 2 D
2 1 R
2 2 D
输出样例:
4
思路:

注意审题,"轮流在相邻的点之间画上红边和蓝边"表示不存在有孤立的线的情况

可以把每个点进行转换,变成一个独特的数,然后我们就可以把每个点存起来,如果新的两个点转化后,发现有共同祖先那就表示封圈了

代码:
#include<bits/stdc++.h>using namespace std;const int N=4e4+9;//因为二维转化为一维了,所以一维空间必须开N的平方级 (200*200) 
int p[N];int find(int x)
{if(x!=p[x])p[x]=find(p[x]);return p[x];
}void merge(int a,int b)
{p[find(a)]=find(b);
}int main()
{int n,m;cin>>n>>m;for(int i=1;i<=n*n;i++)p[i]=i;int cnt=1;for(int i=1;i<=m;i++){int a,b;char c;cin>>a>>b>>c;int p=(a-1)*n+b;//p表示原来的坐标 int q;//q表示另一端(向下或者向右) if(c=='D')q=a*n+b;else q=(a-1)*n+b+1;//cout<<find(p)<<" "<<find(q)<<endl;if(find(p)==find(q)){cout<<i;return 0;}merge(p,q);}cout<<"draw";return 0;
}

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

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

相关文章

flink1.18.0报错 an implicit exists from scala.Int => java.lang.Integer, but

完整报错 type mismatch;found : Int(100)required: Object Note: an implicit exists from scala.Int > java.lang.Integer, but methods inherited from Object are rendered ambiguous. This is to avoid a blanket implicit which would convert any scala.Int to a…

【Java反序列化】CommonsCollections-CC1链分析

前言 好几天没发博文了&#xff0c;偷偷憋了个大的——CC1链分析&#xff0c;手撸了一遍代码。虽然说&#xff0c;这个链很老了&#xff0c;但还是花费了我一段时间去消化吸收&#xff0c;那么接下来&#xff0c;我会简洁的介绍下整个链的利用过程&#xff0c;还有哪些不理解的…

初识C++(一)

目录 一、什么是C 二、关键字&#xff1a; 三、命名空间 &#xff1a; 1. C语言存在的问题&#xff1a; 2. namespace关键字&#xff1a; 3. 注意点&#xff1a; 4.使用命名空间分为三种&#xff1a; 四、输入输出&#xff1a; 五、缺省函数&#xff1a; 1. 什么是缺省…

【Linux】进程地址空间——有这篇就够了

前言 在我们学习C语言或者C时肯定都听过老师讲过地址的概念而且老师肯定还会讲栈区、堆区等区域的概念&#xff0c;那么这个地址是指的物理内存地址吗&#xff1f;这里这些区域又是如何划分的呢&#xff1f; 我们在使用C语言的malloc或者C的new函数开辟空间时&#xff0c;开辟…

栈——数据结构——day4

栈的定义 栈是限定仅在一段进行插入和删除操作的线性表。 我们把允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom),不含任何数据元素的栈称为空栈。栈又称为后进先出(Last In First Out)的线性表&#xff0c;简称LIFO结构。 栈的插入操作&#xff0c;叫作进栈&#…

【收藏】什么是API测试?这是我见过的最全的测试指南!

在最近的部署中&#xff0c;当我被问到“什么是API测试&#xff1f;”时&#xff0c;我正与客户一起制定API测试策略。那时我突然意识到&#xff0c;要描述API测试居然是一件如此具有挑战性的事情&#xff0c;即使你如实地描述了它&#xff0c;也往往听起来很无聊和复杂。 好吧…

第十二届蓝桥杯省赛CC++ 研究生组

十二届省赛题 第十二届蓝桥杯省赛C&C 研究生组-卡片 第十二届蓝桥杯省赛C&C 研究生组-直线 第十二届蓝桥杯省赛C&C 研究生组-货物摆放 第十二届蓝桥杯省赛C&C 研究生组-路径 第十二届蓝桥杯省赛C&C 研究生组-时间显示 第十二届蓝桥杯省赛C&C 研究生组…

AI PPT生成工具 V1.0.0

AI PPT是一款高效快速的PPT生成工具&#xff0c;能够一键生成符合相关主题的PPT文件&#xff0c;大大提高工作效率。生成的PPT内容专业、细致、实用。 软件特点 免费无广告&#xff0c;简单易用&#xff0c;快速高效&#xff0c;提高工作效率 一键生成相关主题的标题、大纲、…

TCP | TCP协议格式 | 三次握手

1.TCP协议 为什么需要 TCP 协议 &#xff1f;TCP 工作在哪一层&#xff1f; IP网络层是不可靠的&#xff0c;TCP工作在传输层&#xff0c;保证数据传输的可靠性。 TCP全称为 “传输控制协议&#xff08;Transmission Control Protocol”&#xff09;。 TCP 是面向连接的、可靠…

YOLOV9训练自己的数据集

1.代码下载地址GitHub - WongKinYiu/yolov9: Implementation of paper - YOLOv9: Learning What You Want to Learn Using Programmable Gradient Information 2.准备自己的数据集 这里数据集我以SAR数据集为例 具体的下载链接如下所示&#xff1a; 链接&#xff1a;https:/…

备战蓝桥杯Day34 - 每日一题

题目描述 解题思路 1.输入数据n&#xff0c;并将字符串类型转换成整数类型 2.求出输入n是2的几次幂&#xff08;调用math库中的求对数的方法&#xff09;&#xff0c;在下面的循环中要用到 3.定义sum和&#xff0c;将抽取到的牌的总数加起来存储 4.count 0 # 记录 2 的第几…

算法打卡day20|二叉树篇09|Leetcode 669. 修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树

算法题 Leetcode 669. 修剪二叉搜索树 题目链接:669. 修剪二叉搜索树 大佬视频讲解&#xff1a;修剪二叉搜索树视频讲解 个人思路 把这道题想复杂了&#xff0c;还想着如何去重构树 解法 递归法 依旧递归三步走 1.确定递归函数的参数以及返回值 这题递归需要返回值&#…

探索人工智能基础:从概念到应用【文末送书-42】

文章目录 人工智能概念人工智能基础【文末送书-42】 人工智能概念 人工智能&#xff08;Artificial Intelligence&#xff0c;AI&#xff09;作为当今科技领域的热门话题&#xff0c;已经深刻地影响着我们的生活和工作。但是&#xff0c;要理解人工智能&#xff0c;我们首先需…

【OpenSSH】Windows系统使用OpenSSH搭建SFTP服务器

【OpenSSH】Windows系统使用OpenSSH搭建SFTP服务器 文章目录 【OpenSSH】Windows系统使用OpenSSH搭建SFTP服务器一、环境说明二、安装配置步骤1.下载完成后&#xff0c;传至服务器或者本机并解压至C:/Program Files/目录下2.打开PowerShell终端3.进入到包含ssh可执行exe文件的文…

物联网和工业物联网的区别——青创智通

工业物联网解决方案-工业IOT-青创智通 物联网&#xff08;IoT&#xff09;和工业物联网&#xff08;IIoT&#xff09;作为现代科技的重要分支&#xff0c;正在逐渐渗透到我们的日常生活和工业生产中。它们的应用范围广泛&#xff0c;涵盖了从智能家居到自动化工厂的多个领域。…

类于对象(上)--- 类的定义、访问限定符、计算类和对象的大小、this指针

在本篇中将会介绍一个很重要和很基础的Cpp知识——类和对象。对于类和对象的篇目将会有三篇&#xff0c;本篇是基础篇&#xff0c;将会介绍类的定义、类的访问限定符符和封装、计算类和对象的大小、以及类的 this 指针。目录如下&#xff1a; 目录 1. 关于类 1.1 类的定义 2 类…

Windows Insiders WSLg Linux GUI App 支持尝鲜

2021 年 4 月 21 日&#xff0c;微软在 Developer Blogs 发布了 Windows 预览版 WSL&#xff08;Windows Linux 子系统&#xff09; 对 Linux GUI App 的支持的公告&#x1f517;&#xff0c;碰巧&#x1f600;我最近重装了波电脑&#xff0c;系统换成了 Windows Insiders&…

Python Flask框架 -- 模版渲染、模版访问对象属性、过滤器与自定义过滤器

模版渲染 使用 render_template 来渲染模板 from flask import Flask, render_templateapp Flask(__name__)app.route(/blog/<blog_id>) def blog_detail(blog_id):return render_template(blog_detail.html, blog_idblog_id, username核)if __name__ __main__:app.r…

ByteTrack多目标跟踪——YOLOX详解

文章目录 1 before train1.1 dataset1.2 model 2 train2.1 Backbone2.2 PAFPN2.3 Head2.3.1 Decoupled Head2.3.2 anchor-free2.3.3 标签分配① 初步筛选② simOTA 2.3.4 Loss计算 项目地址&#xff1a; ByteTrack ByteTrack使用的检测器是YOLOX&#xff0c;是一个目前非常流行…

C++程序变量的引用

在C中&#xff0c;变量的“引用” 就是变量的别名&#xff0c;因此引用又称为别名。由于引用不是独立的变量&#xff0c;编译系统不给它单独分配存储单元&#xff0c;因此在建立引用时只有声明&#xff0c;没有定义&#xff0c;只是声明它和原有的某一变量的关系。 一、引用变更…