【ABC181】F - Silver Woods

题目

题目链接:https://atcoder.jp/contests/abc181/tasks/abc181_f
有一个 \(200\times 2\times 10^9\) 的网格,其中横坐标区间为 \([-100,100]\),纵坐标区间为 \([-10^9,10^9]\)。平面上有若干个点。
你有一个圆,最开始在 \((0,-10^9)\),询问圆半径最大是多少使得它可以在不接触点的情况下圆心到达 \((0,10^9)\)

思路

二分圆的直径,如果两个点之间的距离小于直径,那么显然圆没法从这两个点之间经过。注意要把直线 \(x=100\)\(x=-100\) 也看做一个点。
那么如果连完线之后把直线 \(x=100\)\(x=-100\) 联通,那么相当于存在若干连线将左右两边隔开,这样圆就无法过去。否则可以到达。
用并查集维护即可。
时间复杂度 \(O(n^2\log k)\)

代码

#include <bits/stdc++.h>
using namespace std;

const int N=110;
const double eps=1e-5;
int n,S,T,X[N],Y[N],father[N];

int getdis(int i,int j)
{
	return (X[i]-X[j])*(X[i]-X[j])+(Y[i]-Y[j])*(Y[i]-Y[j]);
}

int find(int x)
{
	return x==father[x]?x:father[x]=find(father[x]);
}

int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		scanf("%d%d",&X[i],&Y[i]);
	S=n+1; T=n+2;
	double l=0,r=200,mid;
	while (r-l>=eps)
	{
		mid=(l+r)/2.0;
		for (int i=1;i<=T;i++) father[i]=i;
		for (int i=1;i<=n;i++)
			for (int j=i+1;j<=n;j++)
				if (getdis(i,j)<mid*mid) father[find(i)]=find(j);
		for (int i=1;i<=n;i++)
		{
			if (100+Y[i]<mid) father[find(i)]=find(S);
			if (100-Y[i]<mid) father[find(i)]=find(T);
		}
		if (find(S)!=find(T)) l=mid;
			else r=mid; 
	}
	printf("%0.10lf\n",l/2.0);
	return 0;
}
posted @ 2020-11-02 07:20  stoorz  阅读(333)  评论(0)    收藏  举报