【洛谷P3958】【NOIP提高组2017】 奶酪

题目传送门

这题很明显可以用并查集,把所有相交的球体都合并成为一条通路,最后枚举判断

#include <bits/stdc++.h>
#define MAX 1005
#define ll long long
using namespace std;

/***并查集***/
int par[MAX];

int find(int x){
	if(par[x] == x)
		return x;
	par[x] = find(par[x]);
	return par[x];
}
bool isConnected(int x, int y){
	return find(x) == find(y);
}
void connect(int x, int y){
	int a = find(x);
	int b = find(y);
	if(a == b) {
		return;
	}
	par[a] = b;
}

/*并查集结束*/


int n;
ll h,r;
struct Pos {
	ll x, y, z;
} a[MAX];

ll sqr(ll x){                   //平方
	return x*x;
}

bool check(Pos p1, Pos p2){                     //判断两个球体是否相交或相切
	ll dist = sqr(p1.x-p2.x) + sqr(p1.y-p2.y) + sqr(p1.z-p2.z);
	//为防止精度损失,采用平方比较
	if(dist <= 4*r*r) {                                     //球心距小于等于半径和,则两圆相切或相交
		return true;                    //4*r*r = (2r)^2, 即两球半径和的平方
	}
	return false;
}

void solve(){
	cin >> n >> h >> r;
	for(int i = 1; i <= n; i++) {
		par[i] = i;
	}
	for (int i = 1; i <= n; i++) {
		scanf("%lld %lld %lld", &a[i].x, &a[i].y, &a[i].z);
	}
	for (int i = 1; i <= n-1; i++) {
		for (int j = i+1; j <= n; j++) {
			if(check(a[i], a[j])) {
				connect(i,j);
			}
		}
	}
	vector<int> v1;                 //在底部的球
	vector<int> v2;                 //在顶部的球
	for (int i = 1; i <= n; i++) {
		if(a[i].z - r <= 0)                     //如果在底部
			v1.push_back(i);
		if(a[i].z + r >= h)                     //如果在顶部
			v2.push_back(i);
	}
	int flag = false;
	for (int i = 0; i < (int)v1.size(); i++) {
		for (int j = 0; j < (int)v2.size(); j++) {
			if(isConnected(v1[i], v2[j])) {                 //如果从底面到顶面有通路
				cout << "Yes" << endl;
				flag = true;
				break;
			}
		}
		if(flag) {
			break;
		}
	}
	if(!flag)
		cout << "No" << endl;
}

int main()
{
	int t;
	cin >> t;
	for (int i = 1; i <= t; i++) {
		solve();
	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_30115697/article/details/82187672