并查集主要是用来查找图中的节点是否连通。
思路:若想求两点是否连通,只用判断两点所在的树的根节点是否相同。若相同则连通,否则不连通。
写法就比如说若编号为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 }