本题我们用到了并查集,首先我们可以由数学知识得到,如果两圆圆心的距离小于其直径,那么两圆相交,之后我们就可以使用并查集将联通的圆合并,之后判断是否有集合与奶酪的上下联通即可。
下面附上代码
#include <iostream>
using namespace std;
int f[1005], a[1005], b[1005], c[1005], f1[1005], f2[1005], t, n, h, r;
int find(int x)
{
if (x != f[x]) f[x] = find(f[x]);
return f[x];
}
long long suan(long long x1, long long x2, long long x3, long long x4, long long x5, long long x6)
{
return (x1 - x2) * (x1 - x2) + (x3 - x4) * (x3 - x4) + (x5 - x6) * (x5 - x6);
}
int main()
{
cin >> t;
while (t--)
{
cin >> n >> h >> r;
int x1 = 0, x2 = 0;
for (int i = 1; i <= n; i++)
{
f[i] = i;
}
for (int i = 1; i <= n; i++)
{
cin >> a[i] >> b[i] >> c[i];
if (c[i] + r >= h)//记录与顶端连接的圆
{
x1++;
f1[x1] = i;
}
if (c[i] - r <= 0)//记录与底端连接的圆
{
x2++;
f2[x2] = i;
}
for (int k = 1; k <= i; k++)//合并集
{
if ((a[i] - a[k]) * (a[i] - a[k]) + (b[i] - b[k]) * (b[i] - b[k]) > 4 * r * r) continue;//防止数据过大
if (suan(a[i], a[k], b[i], b[k], c[i], c[k]) <= 4 * r * r)
{
int a1 = find(i);
int a2 = find(k);
if (a1 != a2) f[a1] = a2;
}
}
}
int k = 0;
for (int j = 1; j <= x1; j++)//查看是否有联通的集合
{
for (int k = 1; k <= x2; k++)
{
if (find(f1[j]) == find(f2[k]))
{
k = 1;
break;
}
}
if (k == 1) break;
}
if (k == 1) cout << "Yes" << endl;
else cout << "No" << endl;
}
return 0;
}