先來看看題
【題目描述】
現有一塊大奶酪,它的高度爲 h,它的長度和寬度我們可以認爲是無限大的,奶酪中間有許多半徑相同的球形空洞。我們可以在這塊奶酪中建立空間座標系,在座標系中,奶酪的下表面爲z = 0,奶酪的上表面爲z = h。
現在,奶酪的下表面有一隻小老鼠 Jerry,它知道奶酪中所有空洞的球心所在的座標。
如果兩個空洞相切或是相交,則 Jerry 可以從其中一個空洞跑到另一個空洞,特別地,如果一個空洞與下表面相切或是相交,Jerry 則可以從奶酪下表面跑進空洞;如果一個空洞與上表面相切或是相交,Jerry 則可以從空洞跑到奶酪上表面。
位於奶酪下表面的 Jerry 想知道,在不破壞奶酪的情況下,能否利用已有的空洞跑到奶酪的上表面去?
空間內兩點P(x ,y ,z )、P(x ,y ,z )的距離公式如下:
dist(p1,p2)=sqrt((x1-x2)^2 +(y1-y2)^2 +(z1-z2)^2)
【輸入格式】
輸入文件名爲 cheese.in。
每個輸入文件包含多組數據。
輸入文件的第一行,包含一個正整數 T,代表該輸入文件中所含的數據組數。
接下來是 T 組數據,每組數據的格式如下:
第一行包含三個正整數 n,h 和 r,兩個數之間以一個空格分開,分別代表奶酪中空洞的數量,奶酪的高度和空洞的半徑。
接下來的 n 行,每行包含三個整數 x、y、z,兩個數之間以一個空格分開,表示空洞球心座標爲(x, y, z)。
【輸出格式】
輸出文件名爲 cheese.out。
輸出文件包含 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 = 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。
““時間限制:1s 空間限制:256MB””
思路分享
這道題不要想得過於複雜,把每個洞想象成一個點(球心),雖然每個點有x,y,z三個量定義,但通過公式可以將其任意兩點間的距離求出,既任意兩球心都處在同一平面內(儘管這個平面不平行於奶酪的任意麪,但這不重要)。
現在我們已成功將三維關係轉化成一維關係,可以通過刨面圖來分析。【此時並查集出場】只要兩點相同,就可以將它們併成一個集合。其實並查集很好想,就是在代碼實現的時候應注意人工製造cheese【0】和cheese【1001】,默認其聯通奶酪上下表面。各個點看看能不能連上包括【0】【1001】的其他點,過程套並查集模板即可。
代碼分享
(c++)
#include<bits/stdc++.h>
#define SIZE 1010
using namespace std;
int cheese[SIZE];
double x[SIZE],y[SIZE],z[SIZE];
long n,h,r;
double math(double xxx,double yyy,double zzz,double xx,double yy,double zz)
{
double sum=sqrt((xxx-xx)*(xxx-xx)+(yyy-yy)*(yyy-yy)+(zzz-zz)*(zzz-zz));
return sum;
}
int find(int root)
{
if(cheese[root]!=root)
cheese[root]=find(cheese[root]);
return cheese[root];
}
int main()
{
//freopen("cheese.in","r",stdin);
//freopen("cheese.out","w",stdout);
int i,j,t,bl;
scanf("%d",&t);
for(bl=1;bl<=t;bl++)
{
scanf("%ld%ld%ld",&n,&h,&r);
for(i=0;i<=1001;i++)
cheese[i]=i;//cheese[0] cheese[1001]
for(i=1;i<=n;i++)
{
scanf("%lf%lf%lf",&x[i],&y[i],&z[i]);
if(z[i]+r>=h)
{
int r1=find(i);
int r2=find(1001);
cheese[r1]=r2;
}//ding
if(z[i]-r<=0)
{
int r1=find(i);
int r2=find(0);
cheese[r1]=r2;
}//di
for(j=1;j<i;j++)
{
if(math(x[i],y[i],z[i],x[j],y[j],z[j])<=2*r)
{
int r1=find(i);
int r2=find(j);
cheese[r1]=r2;
}
}
}
int r1=find(0);
int r2=find(1001);
if(r1==r2) cout<<"Yes"<<endl;
if(r1!=r2) cout<<"No"<<endl;
}
//fclose(stdin);
//fclose(stdout);
return 0;
}