[NOIp2017 Day2 T1] 奶酪cheese(並查集)

題目

描述

現有一塊大奶酪,它的高度爲 h ,它的長度和寬度我們可以認爲是無限大的,奶酪中間有許多半徑相同的球形空洞。我們可以在這塊奶酪中建立空間座標系,在座標系中,奶酪的下表面爲z=0 ,奶酪的上表面爲z=h
現在,奶酪的下表面有一隻小老鼠 Jerry,它知道奶酪中所有空洞的球心所在的坐 標。如果兩個空洞相切或是相交,則 Jerry 可以從其中一個空洞跑到另一個空洞,特別地,如果一個空洞與下表面相切或是相交,Jerry 則可以從奶酪下表面跑進空洞;如果一個空洞與上表面相切或是相交,Jerry 則可以從空洞跑到奶酪上表面。
位於奶酪下表面的 Jerry 想知道,在不破壞奶酪的情況下,能否利用已有的空洞跑到奶酪的上表面去?
空間內兩點P1(x1,y1,z1)P2(x2,y2,z2) 的距離公式如下:

dist(P1,P2)=(x1x2)2+(y1y2)2+(z1z2)2

輸入

每個輸入文件包含多組數據。
輸入文件的第一行,包含一個正整數 T ,代表該輸入文件中所含的數據組數。
接下來是 T 組數據,每組數據的格式如下: 第一行包含三個正整數 n,hr ,兩個數之間以一個空格分開,分別代表奶酪中空洞的數量,奶酪的高度和空洞的半徑。
接下來的 n 行,每行包含三個整數 x,y,z ,兩個數之間以一個空格分開,表示空洞球心座標爲(x,y,z)

輸出

輸出文件包含 T 行,分別對應 T 組數據的答案,如果在第 i 組數據中,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

數據規模與約定

對於 20%的數據,n=11h,r10,000 ,座標的絕對值不超過 10,000。

對於 40%的數據,1n81h,r10,000 ,座標的絕對值不超過 10,000。

對於80%的數據, 1n1,0001h,r10,000 ,座標的絕對值不超過10,000。

對於 100%的數據,1n1,0001h,r1,000,000,000T20 ,座標的絕對值不超過 1,000,000,000。

解題思路

設下底面爲點S=n+1 ,上底面爲點T=n+2 ,枚舉兩個點看它們是否連通,連通即將它們用並查集並起來,最後看ST 是否連通即可。

Code

#include<cstdio>
#include<cmath>

using namespace std;

typedef long long LL;
typedef long double LB;
const int N = 1005;
int CASES, n, h, S, T;
LL r;

struct Node{
    int x, y, z;
}node[N];

inline LB dist(int a, int b){
    return sqrt((LB)(node[a].x-node[b].x)*(node[a].x-node[b].x)+(LB)(node[a].y-node[b].y)*(node[a].y-node[b].y)+(LB)(node[a].z-node[b].z)*(node[a].z-node[b].z));
}

int fa[N];
void init(){
    for(int i = 1; i <= n+2; i++)   fa[i] = i;
}
int findfa(int x){
    if(fa[x] != x)  fa[x] = findfa(fa[x]);
    return fa[x];
}
void unionn(int x, int y){
    fa[findfa(y)] = findfa(x);
}

int main(){
    scanf("%d", &CASES);
    while(CASES--){
        scanf("%d%d%lld", &n, &h, &r);
        init();
        S = n + 1, T = n + 2;
        for(int i = 1; i <= n; i++){
            scanf("%d%d%d", &node[i].x, &node[i].y, &node[i].z);
            for(int j = 1; j < i; j++){
                if(dist(i, j) <= 2 * r && findfa(i) != findfa(j))
                    unionn(i, j);
            }
            if(node[i].z + r >= h)  unionn(i, T);
            if(node[i].z - r <= 0)  unionn(i, S);
        }
        if(findfa(T) == findfa(S))  puts("Yes");
        else    puts("No");
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章