NOIP2017提高组D2T1 奶酪 解析

这显然是一道并查集(如果没有学过并查集的童鞋还是去找找别的博客吧)

思路比较简单,就是如果两个洞相交(或相切),就把它们连入一个集合,可以想象一个集合就是一条通道

我们只需要判断每一条通道是否存在元素与底部、顶部相连即可。如果都有,那么输出Yes
那么问题来了,如何判断两个球是否相交(切)呢?
其实如果你数学很好、做题经验丰富 ,你就会知道了:
如果两个球的半径之和>=两个球球心的距离,那么两圆相交(切)。(emm这应该很容易想到)

具体操作看注释

//注释&代码 @copyright lzoi_hmh 
//并查集 
#include 
#include 
#include 
#define MAXN 1001
#define ll long long
using namespace std;

//fa[i]为并查集模板操作,表示第i个洞的祖先 
//tot_top表示通到顶上的洞的个数,tot_bottom表示通到底部的洞的个数 
//top[i]表示第i个通到顶上的洞,bottom[i]表示第i个通到底部的洞  
int fa[MAXN],t,n,top[MAXN],bottom[MAXN],tot_top,tot_bottom;
ll x[MAXN],y[MAXN],z[MAXN],r,h;

int find(int x)  //找祖先 
{
	if (x!=fa[x]) fa[x]=find(fa[x]);
	return fa[x];
}

double cnt_dis(ll x,ll y, ll z,ll x1, ll y1,ll z1) //计算两圆心之间的距离 
{
	double ans;
	ans=sqrt((x-x1)*(x-x1) + (y-y1)*(y-y1) + (z-z1)*(z-z1));
	return ans;
}

int main()
{
	scanf("%d",&t);
	for (int i=1;i<=t;i++){
		scanf("%d %lld %lld",&n,&h,&r);
		tot_top=0; tot_bottom=0;
		for (int j=1;j<=n;j++){ //并查集初始操作 
			fa[j]=j;
		}
		for (int j=1;j<=n;j++){
			scanf("%lld %lld %lld",&x[j],&y[j],&z[j]);
			if (z[j]+r>=h){   //找所有通到顶部的洞 
				tot_top++;
				top[tot_top]=j;
			}
			if (z[j]-r<=0){   //找所有通到底部的洞 
				tot_bottom++;
				bottom[tot_bottom]=j;
			}
			for (int k=1;k

你可能感兴趣的:(noip,题目解析,详解)