XiaoHuang's Space
XiaoHuang's Space
XiaoHuang
May the force be with you.
『题解』洛谷P3958 奶酪
Posted: Dec 11, 2019
Last Modified: Dec 13, 2019
This article was last modified days ago. The content of this post may be outdated!

Portal

Portal1: Luogu

Portal2: LibreOJ

Portal3: Vijos

Description

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

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

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

空间内两点$P_1(x_1, y_1, z_1)$、$P_2(x_2, y_2, z_2)$的距离公式如下:

$$\operatorname{dist}(P_1, P_2) = \sqrt{(x_1 - x_2) ^ 2 + (y_1 - y_2) ^ 2 + (z_1 - z_2) ^ 2}$$

Input

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

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

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

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

Output

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

Sample Input

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

Sample Output

Yes
No
Yes

Sample Explain

Hint

数据规模与约定:

对于$20\%$的数据,$n = 1, 1 \le h, r \le 10,000$,坐标的绝对值不超过$10,000$;

对于$40\%$的数据,$1 \le n \le 8, 1 \le h, r \le 10,000$,坐标的绝对值不超过$10,000$。

对于$80\%$的数据,$1 \le n \le 1,000, 1 \le h , r \le 10,000$,坐标的绝对值不超过$10,000$。

对于$100\%$的数据,$1 \le n \le 1,000, 1 \le h , r \le 1,000,000,000,T \le 20$,坐标的 绝对值不超过$1,000,000,000$。

Solution

这题并查集。

Code

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>

using namespace std;

typedef long long LL;
const int MAXN = 1005;
int T;
LL n, h, r, x[MAXN], y[MAXN], z[MAXN], father[MAXN];
inline LL read() {
    char ch = getchar();
    LL x = 0, f = 1;
    while (ch < '0' || ch > '9') {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while ('0' <= ch && ch <= '9') {
        x = (x << 1) + (x << 3) + ch - '0';
        ch = getchar();
    }
    return x * f;
}
inline LL find(LL x) {//找父亲
    return father[x] == x ? x : find(father[x]);//路径压缩
}
inline LL check(LL p, LL q) {
    if ((x[p] - x[q]) * (x[p] - x[q]) + (y[p] - y[q]) * (y[p] - y[q]) + (z[p] - z[q]) * (z[p] - z[q]) <= r * r * 4) return 1; else return 0;
}
int main() {
    T = read();
    while (T--) {
        n = read(); h = read(); r = read();
        for (LL i = 0; i <= n + 1; i++)
            father[i] = i;
        for (LL i = 1; i <= n; i++) {
            x[i] = read(); y[i] = read(); z[i] = read();
            if (fabs(z[i]) <= r) father[find(i)] = find(0);
            if (fabs(h - z[i]) <= r) father[find(i)] = find(n + 1);
            for (LL j = 1; j < i; j++)
                if (check(i, j)) father[find(j)] = find(i);
        }
        if (find(0) == find(n + 1)) printf("Yes\n"); else printf("No\n");
    }
    return 0;
}

Attachment

测试数据下载:https://www.lanzous.com/i5gntle

Article License: CC BY-NC-ND 4.0
Article Author: XiaoHuang
  1. 1. Portal
  2. 2. Description
  3. 3. Input
  4. 4. Output
  5. 5. Sample Input
  6. 6. Sample Output
  7. 7. Sample Explain
  8. 8. Hint
  9. 9. Solution
  10. 10. Code
  11. 11. Attachment
Newer Post
『题解』洛谷P4936 Agent1
Older Post
『题解』洛谷P2296 寻找道路
Buy me a beer?
-->
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×