Gym

题目链接

题目大意

  略

解题思路

  题目要求最大的可通过半径,很容易想到二分,但是直接二分的话,情况会变得比较复杂。换个角度想一下,可以把这个人的半径“加”到各个圆和上下边界上,这样只要判断两个圆的关系已经圆与上下边界的关系就行了。
  对于我们二分的半径来说,两个圆之间的距离不够这个人通过,那么能否通过两个圆就取决于两个圆与上下边界的距离,把这两个圆看做一个整体,加入第三个圆,亦是如此。所以说可以用并查集把那些间距不够这个人通过的圆都加入一个集合里。

代码

const int maxn = 1e3+10;
const int maxm = 2e5+10;
struct INFO {
	int x, y, r;
} info[maxn];
int w, n, p[maxn];
double u[maxn], d[maxn];
int find(int x) {
	return p[x]==x ? p[x]:p[x]=find(p[x]);
}
double dis(int i, int j) {
	return 1.0*(info[i].x-info[j].x)*(info[i].x-info[j].x)+1.0*(info[i].y-info[j].y)*(info[i].y-info[j].y);
}
bool check(double x) {
	for (int i = 1; i<=n; ++i) p[i] = i;
	for (int i = 1; i<=n; ++i) {
		u[i] = info[i].y+info[i].r+x;
		d[i] = info[i].y-info[i].r-x;
		for (int j = 1; j<i; ++j) {
			double a = dis(i, j);
			double b = (info[i].r+info[j].r+2*x)*(info[i].r+info[j].r+2*x);
			if (a<b) {
				int fi = find(i), fj = find(j);
				p[fi] = fj;
				u[fj] = max(u[fi], u[fj]);
				d[fj] = min(d[fi], d[fj]);
			}
		}
	}
	for (int i = 1; i<=n; ++i)
		if (u[i]>w-x && d[i]<x) return 0;
	return 1;
}
int main() {
	int T; cin >> T;
	while(T--) {
		cin >> w >> n;
		for (int i = 1; i<=n; ++i) {
			scanf("%lld%lld%lld", &info[i].x, &info[i].y, &info[i].r);
		}
		double l = 0, r = w/2.0;
		for (int i = 1; i<=100; ++i) {
			double mid = (l+r)/2;
			//cout << mid << endl;
			if (check(mid)) l = mid;
			else r = mid;
		}
		printf("%.7f
", l);
	}
	return 0;
}


原文地址:https://www.cnblogs.com/shuitiangong/p/14366751.html