并查集

并查集主要是用来查找图中的节点是否连通。

思路:若想求两点是否连通,只用判断两点所在的树的根节点是否相同。若相同则连通,否则不连通。

写法就比如说若编号为1的结点能连到2,2能连到3,那么1和2就都连到3。就是不断降低树的深度。像下图一样

 

主要代码

 1 int p[1005];  //p[i]表示节点i的根节点
 2 void init()    //初始化
 3 {
 4     for(int i = 0; i < 1005; ++i) p[i] = i;
 5     return;
 6 }
 7 int Find(int x)
 8 {
 9     return x == p[x] ? x : p[x] = Find(p[x]);  //找到该节点的根节点
10 }
11 void merge(int a, int b)  //合并
12 {
13     int pa = Find(a), pb = Find(b);
14     if(pa == pb) return;  //若已经连通,则什么都不用做
15     else p[pa] = pb;    //p[pb] = pa 一样    
16     return;
17 }

应用:

比如说noip2017day2T1

题目描述

现有一块大奶酪,它的高度为 h,它的长度和宽度我们可以认为是无限大的,奶酪 中间有许多 半径相同 的球形空洞。我们可以在这块奶酪中建立空间坐标系,在坐标系中, 奶酪的下表面为z = 0,奶酪的上表面为z = h。

现在,奶酪的下表面有一只小老鼠 Jerry,它知道奶酪中所有空洞的球心所在的坐 标。如果两个空洞相切或是相交,则 Jerry 可以从其中一个空洞跑到另一个空洞,特别 地,如果一个空洞与下表面相切或是相交,Jerry 则可以从奶酪下表面跑进空洞;如果 一个空洞与上表面相切或是相交,Jerry 则可以从空洞跑到奶酪上表面。

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

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

dist(P1,P2)=sqrt{(x1 * x2)^2 + (y1 * y2)^2 + (z1 * z2)^2}

输入输出格式

输入格式:

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

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

接下来是 TT 组数据,每组数据的格式如下: 第一行包含三个正整数 n,hn,h 和 rr,两个数之间以一个空格分开,分别代表奶酪中空 洞的数量,奶酪的高度和空洞的半径。

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

输出格式:

输出文件包含 TT 行,分别对应 TT 组数据的答案,如果在第 ii 组数据中,Jerry 能从下 表面跑到上表面,则输出Yes,如果不能,则输出No (均不包含引号)。

输入输出样例

输入样例

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

代码
 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 typedef long long ll; 
 5 int t;
 6 ll x[1005], y[1005], z[1005];
 7 int p[1005];
 8 void init()
 9 {
10     for(int i = 0; i < 1005; ++i) p[i] = i;
11     return;
12 }
13 int Find(int x)
14 {
15     return x == p[x] ? x : p[x] = Find(p[x]);
16 }
17 void merge(int a, int b)
18 {
19     int pa = Find(a), pb = Find(b);
20     if(pa == pb) return;
21     else p[pa] = pb;
22     return;
23 }
24 int main()
25 {
26     scanf("%d", &t);
27     while(t--)
28     {
29         init();
30         int n;
31         ll h, r;
32         scanf("%d%lld%lld", &n, &h, &r);
33         for(int i = 1; i <= n; ++i)
34         {
35             scanf("%lld%lld%lld", &x[i], &y[i], &z[i]);
36             for(int j = 1; j < i; ++j)
37             {
38                 ll dis = (x[i] - x[j]) * (x[i] - x[j]) +  
39                          (y[i] - y[j]) * (y[i] - y[j]) + 
40                          (z[i] - z[j]) * (z[i] - z[j]);
41                 if(dis <= 4 * r * r) merge(i, j);
42             }
43             if(z[i] <= r) merge(i, 0);      //设下表面是0节点,上表面是n + 1 节点
44             if(z[i] + r >= h) merge(i, n + 1);
45         }
46         
47         if(Find(0) == Find(n + 1)) printf("Yes\n");  //最后只用判断0节点和 n + 1 节点的根节点是否相同就行
48         else printf("No\n");
49     }
50     return 0;
51 }

 

原文地址:https://www.cnblogs.com/mrclr/p/8150723.html