2018 ICPC 沈阳网络赛 The cake is a lie

题意:

给出n个半径一致的圆,画一个圆至少完全包含其中的m个,求最小半径。

题解:

可化简为,n个点,求覆盖掉至少m个的最小的圆

O(n^2logn *logR)的解法:

二分半径,然后判断这个半径下能覆盖的最多的点,若小于要求,半径变大,若大于要求,半径缩小。

如何得知一个半径下能覆盖的最多的点?

设半径为r

我们枚举每一个点,表示一定要包含的点,我们在包含住这个点的前提下尽量包含更多的点。

找出所有的与枚举的点距离小于等于2*r的点,以这些点为圆心画半径为r的圆会与枚举的点画的圆有交点。

交点与枚举的点之间形成一段角度,其含义是当圆心在那个角度的范围内画圆时,可以同时包含2个点。

那我们要找的是一个角度,它被最多的上文提到的“一段角度”覆盖。

找的方法是在端点标记1,-1,排序后求前缀和。

代码:

#include<bits/stdc++.h>
#define N 1010
#define mod 1000000007
#define INF 1e17
#define eps 1e-8
#define pi 3.141592653589793
#define LL unsigned long long
#define pb push_back
#define cl clear
#define si size
#define lb lowwer_bound
#define mem(x) memset(x,0,sizeof x)
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;

int dcmp(double x){if (fabs(x)<eps)return 0;else return x<0?-1:1;}

struct Point
{
    double x,y;
    Point(double x=0,double y=0):x(x),y(y){ }
    void read(){scanf("%lf%lf",&x,&y);}
}a[N];

double dis(Point a,Point  b)
{
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

struct cc
{
	double x; int fg;
	bool operator < (const cc z)const
	{
		return dcmp(x-z.x)<=0 || dcmp(x-z.x)==0 && fg>z.fg;
	}
}v[N];

int check(double r,int n)
{
	int f=0;
	for (int i=1;i<=n;i++)
	{
		int res=0,tot=0;
		for (int j=1;j<=n;j++)
		{
			double R=dis(a[i],a[j]);
			if (dcmp(R-r*2)>0) continue;
			if (dcmp(R)==0) res++;else
			{
				double ang=acos(max(-1.0,min(1.0,R*0.5/r)));
				double A=atan2(a[j].y-a[i].y,a[j].x-a[i].x);
				if (dcmp(A)<0) A+=pi*2;
				A+=pi*2;
				v[++tot].x=A-ang; v[tot].fg=1;
				v[++tot].x=A+ang; v[tot].fg=-1;
			}
		}
		sort(v+1,v+tot+1);
		f=max(f,res);
		for (int i=1;i<=tot;i++)
		{
			res+=v[i].fg;
			f=max(f,res);
		}
	}
	return f;
}

int main()
{
	int T;
	sc(T);
	while(T--)
	{
		int n,m; double R;
		scc(n,m); for (int i=1;i<=n;i++) a[i].read(); scanf("%lf",&R);
		if (m>n)
		{
			puts("The cake is a lie.");continue;
		}
		double l=0,r=1e4;
		while(r-l>1e-6)
		{
			double t=(l+r)*0.5;
			if (check(t,n)>=m)r=t;else l=t;
		}
		printf("%.4f\n",r+R);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/nudt_spy/article/details/82599013