题解:P3958 [NOIP2017 提高组] 奶酪

思路

不妨考虑并查集数据结构,对于并查集这种数据结构不再阐述,相关内容请学会使用搜索引擎。

既然要从一个洞口到另一个洞口,那么就把这两个洞口放到一个集合(即可以通过)里。

那是不是所有的洞口都能合并呢?显然不行,那这样就一定有解了。

怎样才能将两个洞口合并呢?如果两个洞口的圆心的直线距离不大于(即小于或等于)两个半径,就可以将这两个洞口合并。

代码

去年的去年的代码:

#include<bits/stdc++.h> 
using namespace std;
#define maxn 1010
int n,h,r,fa[maxn],T;
int x[maxn],y[maxn],z[maxn];

int find(int x){
	if(fa[x] == x) return x;
	return fa[x] = find(fa[x]);
}
void uni(int x, int y){
	int rx = find(x), ry = find(y);
	if(rx == ry) return;
	fa[ry] = rx;
}
void init(){for(int i = 0;i <= n+1;i++) fa[i] = i;}
double squ(double x){return x * x;} 
double dis(double x1,double y1,double z1,double x2,double y2,double z2){return (double)((double)squ(x1-x2) + (double)squ((y1-y2)) + (double)squ((z1-z2)));}

int main(){
	cin>>T;
	while(T--){
		cin>>n>>h>>r;
		init();
		for(int i = 1;i <= n;i++){
			cin>>x[i]>>y[i]>>z[i];
			// 进行洞口和洞口(即通道)的合并操作
			if(abs(z[i] - 0) <= r) uni(0,i);
			if(abs(z[i] - h) <= r) uni(n+1,i);
			for(int j = 1;j < i;j++){if(4LL * r * r >= dis(x[i],y[i],z[i],x[j],y[j],z[j])) uni(i,j);}
		}
		if(find(0) == find(n+1)) cout<<"Yes"<<endl; // 判断起点和奶酪表面是不是在一个集合里,也就是说能不能到达
		else cout<<"No"<<endl;
	}
	return 0;
}