奶酪 链接:https://ac.nowcoder.com/acm/contest/23156/1012 来源:牛客网
题目描述 现有一块大奶酪,它的高度为 h,它的长度和宽度我们可以认为是无限大的,奶酪中间有许多半径相同的球形空洞。我们可以在这块奶酪中建立空间坐标系, 在坐标系中,奶酪的下表面为 z = 0,奶酪的上表面为 z = h。 现在, 奶酪的下表面有一只小老鼠 Jerry, 它知道奶酪中所有空洞的球心所在的坐标。如果两个空洞相切或是相交,则 Jerry 可以从其中一个空洞跑到另一个空洞,特别地,如果一个空洞与下表面相切或是相交, Jerry 则可以从奶酪下表面跑进空洞; 如果一个空洞与上表面相切或是相交, Jerry 则可以从空洞跑到奶酪上表面。 位于奶酪下表面的 Jerry 想知道, 在不破坏奶酪的情况下,能否利用已有的空洞跑到奶酪的上表面去?
输入描述: 每个输入文件包含多组数据。 输入文件的第一行,包含一个正整数 T,代表该输入文件中所含的数据组数。 接下来是 T 组数据,每组数据的格式如下: 第一行包含三个正整数 n, h 和 r, 两个数之间以一个空格分开,分别代表奶酪中空洞的数量,奶酪的高度和空洞的半径。 接下来的 n 行,每行包含三个整数 x, y, z, 两个数之间以一个空格分开, 表示空洞球心坐标为 (x,y,z)。
输出描述: 输出文件包含 T 行,分别对应 T 组数据的答案,如果在第 i 组数据中, Jerry 能从下表面跑到上表面,则输出“Yes”,如果不能,则输出“No”(均不包含引号)。
示例1
输入
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
题目大意:让我们判断能否利用空洞从下表面走到上表面,相交或者相切的空洞可以相互穿梭,这很容易联想到连通块
解决思路:可以用并查集解决连通块问题,用两个变量limit0,limit1分别代表上表面和下表面,遍历每个空洞,每次遍历检查该空洞是否和上下表面连接,如果连接就进行合并,同时还需要遍历该空洞之前的空洞,看之前是否有空洞和该空洞相交或者相切,有的话进行合并,最后检查limit0和limit1是否在一个联通块内即可。
代码实现:
t = int(input())
# 带路径压缩的并查集
def find(x):
if x != fa[x]:
fa[x] = find(fa[x])
return fa[x]
for _ in range(t):
n,h,r = map(int,input().split())
fa = list(range(n+2)) # 初始化fa数组
limit0,limit1 = n,n+1 # 顶和底
x = [0] * n
y = [0] * n
z = [0] * n
for i in range(n):
a,b,c = map(int,input().split())
x[i],y[i],z[i] = a,b,c
# 判断是否和上表面连接
if c + r >= h:
fa[find(i)] = find(limit0)
# 判断是否和下表面连接
if c - r <= 0:
fa[find(i)] = find(limit1)
# 遍历i之前的空洞,看是否有可以连通的
for j in range(i):
if (x[j]-a) * (x[j]-a) + (y[j]-b) * (y[j]-b) + (z[j]-c) * (z[j]-c) <= 4*r*r:
fa[find(i)] = find(j)
if find(limit0) == find(limit1): # 检查上下表面是否连通
print('Yes')
else:
print('No')