思路:
用并查集维护所有相交的球,设置两个哨兵st和ed,分别表征z=0平面和z=h平面,最后判断st和ed是否在同一个集合里即可。
代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; ll t, n, h, r, pre[1005]; int st, ed; struct data { ll x, y, z; }d[1005]; void ini() { pre[st]=st, pre[ed]=ed; for(int i=1;i<=n;++i)//并查集初始化 pre[i]=i; } int findPre(int x) { if(pre[x]==x) return x; return x=findPre(pre[x]);//路径压缩 } void uni(int x, int y) { ll fx=findPre(x), fy=findPre(y); pre[fx]=fy;//fy作为fx的父亲(fx=fy也无所谓,不影响式子正确性) } ll mul(ll x) {return x*x;} bool check(int x, int y) {return findPre(x)==findPre(y);} int main() { cin>>t; while(t--){ cin>>n>>h>>r; st=0, ed=n+1; ini(); for(int i=1;i<=n;++i){ cin>>d[i].x>>d[i].y>>d[i].z; if(abs(d[i].z)<=r) uni(st, i); if(abs(h-d[i].z)<=r) uni(ed, i); } for(int i=1;i<=n;++i) for(int j=i+1;j<=n;++j) if(mul(d[i].x-d[j].x)+mul(d[i].y-d[j].y)+mul(d[i].z-d[j].z)<=4*r*r) uni(i, j); if(check(st, ed)) cout<<"Yes"<<endl; else cout<<"No"<<endl; } return 0; }
另一种写法:不设置哨兵,查询到符合条件的就返回1,一直查询不到就返回0,注意只有一个元素的情况,以及可能爆ll(设置unsigned long long即可)
代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; ll t, n, h, r, pre[1005]; struct data { ll x, y, z; }d[1005]; void ini() { for(int i=1;i<=n;++i) pre[i]=i; } int findPre(int x) { if(pre[x]==x) return x; return x=findPre(pre[x]); } void uni(int x, int y) { ll fx=findPre(x), fy=findPre(y); if(fx==fy) return; pre[fx]=fy; } ll mul(ll x) {return x*x;} bool commonPre(int x, int y) {return findPre(x)==findPre(y);} bool check() { for(int i=1;i<=n;++i) for(int j=i+1;j<=n;++j) if(mul(d[i].x-d[j].x)+mul(d[i].y-d[j].y)+mul(d[i].z-d[j].z)<=4LL*r*r) uni(i, j); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j)//有向,不能从i+1开始遍历 if(commonPre(i, j)&&abs(d[i].z)<=r&&abs(h-d[j].z)<=r) return 1; return 0; } int main() { cin>>t; while(t--){ cin>>n>>h>>r; ini(); for(int i=1;i<=n;++i) cin>>d[i].x>>d[i].y>>d[i].z; if(check()) cout<<"Yes"<<endl; else cout<<"No"<<endl; } return 0; }