奶酪-並查集

先來看看題

【題目描述】

現有一塊大奶酪,它的高度爲 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章