1. 程式人生 > >【NOIP2017提高組】乳酪

【NOIP2017提高組】乳酪

                                                  乳酪

題目背景

NOIP2017提高組 DAY2 T1

題目描述

現有一塊大乳酪,它的高度為h,它的長度和寬度我們可以認為是無限大的,乳酪中間有許多半徑相同的球形空洞。我們可以在這塊乳酪中建立空間座標系,在座標系中,乳酪的下表面為 z=0,乳酪的上表面為 z=h 。

現在,乳酪的下表面有一隻小老鼠 Jerry,它知道乳酪中所有空洞的球心所在的座標。如果兩個空洞相切或是相交,則 Jerry 可以從其中一個空洞跑到另一個空洞,特別地,如果一個空洞與下表面相切或是相交,Jerry 則可以從乳酪下表面跑進空洞;如果一個空洞與上表面相切或是相交,Jerry 則可以從空洞跑到乳酪上表面。

位於乳酪下表面的 Jerry 想知道,在不破壞乳酪的情況下,能否利用已有的空洞跑到乳酪的上表面去? 

空間內兩點 P1 (x1,y1,z1)、P2 (x2,y2,z2) 的距離公式如下:

輸入格式

每個輸入檔案包含多組資料。
輸入檔案的第一行,包含一個正整數T,代表該輸入檔案中所含的資料組數。
接下來是 T 組資料,每組資料的格式如下:
第一行包含三個正整數 n,h 和 r,兩個數之間以一個空格分開,分別代表乳酪中空洞的數量,乳酪的高度和空洞的半徑。
接下來的 n 行,每行包含三個整數 x、y、z,兩個數之間以一個空格分開,表示空洞球心座標為 (x,y,z) 。

輸出格式

輸出檔案包含 T 行,分別對應 T 組資料的答案,如果在第i組資料中,Jerry 能從下表面跑到上表面,則輸出“Yes”,如果不能,則輸出“No”(均不包含引號)。

樣例資料 1

輸入


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

備註

第一組資料,由乳酪的剖面圖可見:

第一個空洞在(0,0,0)與下表面相切
第二個空洞在(0,0,4)與上表面相切
兩個空洞在(0,0,2)相切
輸出Yes

第二組資料,由乳酪的剖面圖可見:

兩個空洞既不相交也不相切
輸出No

第三組資料,由乳酪的剖面圖可見:

兩個空洞相交
且與上下表面相切或相交
輸出Yes

【資料規模與約定】 
對於 20% 的資料,n=1;1≤h,r≤10,000;座標的絕對值不超過 10,000。
對於 40% 的資料,1≤n≤8;1≤h,r≤10,000;座標的絕對值不超過 10,000。 
對於 80% 的資料,1≤n≤1,000;1≤h,r≤10,000;座標的絕對值不超過 10,000。 
對於 100% 的資料,1≤n≤1,000;1≤h,r≤1,000,000,000;T≤20;座標的絕對值不超過 1,000,000,000。 

解析:

       並查集就可以了,BFS也行,但我覺得並查集很直觀啊。

程式碼:

#include <bits/stdc++.h>
using namespace std;
const int Max=1010;
int t,n,h,r,flag,father[Max];
struct shu{long long x,y,z;};
shu a[Max];
inline int get_int()
{
   int x=0,f=1;
   char c;
   for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
   if(c=='-') {f=-1;c=getchar();}
   for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
   return x*f;
}
inline bool comp(const shu &a,const shu &b){return a.z<b.z;}
inline double calc(int i,int j){return sqrt(double(a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y)+(a[i].z-a[j].z)*(a[i].z-a[j].z));}
inline int getfather(int v){return father[v]==v ? v : father[v]=getfather(father[v]);}
int main()
{
   t=get_int();
   while(t--)
   {
   	 memset(a,0,sizeof(a));
   	 n=get_int(),h=get_int(),r=get_int();
   	 for(int i=1;i<=n;i++) a[i].x=get_int(),a[i].y=get_int(),a[i].z=get_int();
   	 sort(a+1,a+n+1,comp);
   	 for(int i=1;i<=n;i++) father[i]=i;
   	 if(a[n].z+r<h || a[1].z>r) {cout<<"No\n";continue;}
     for(int i=1;i<=n;i++)
       for(int j=i+1;j<=n;j++)
       	 if(calc(i,j)<=2*r)
       	 {
       	   int fax=getfather(i),fay=getfather(j);
       	   if(fax!=fay) father[fay]=fax;
       	 }
     flag=0;
     for(int i=n;i>=1;i--)
     {
       if(flag) break;
       if(a[i].z+r<h || flag) break;
       for(int j=1;j<=n;j++)
	   {
	   	 if(a[j].z>r) break;
	     if(getfather(j)==getfather(i)&&a[j].z+r>=0) {flag=1;break;}
	   }
     }
     cout<<(flag ? "Yes\n" : "No\n");
   }

   return 0;
}