HDU--3264[Open-air shopping malls] 枚举圆心+二分半径

题意:
平面上有n个圆,给定他们各自的圆心和半径。保证任意两个圆不会互相重叠。现在求一个大圆,它的圆心与某个给定圆的圆心重合,且对于每一个给定的圆,大圆至少覆盖该圆面积的一半。请求得满足要求的大圆的最小半径。


算法流程
枚举圆心位置Oi。
二分查找,求得对于当前圆心位置,满足要求的最小半径ri
记录上述所有ri中的最小值,并且输出结果。

 

时间复杂度
O(n2logn)

注意:只有一个点的情况

 

CODE:

/*枚举圆心+二分半径*/
/*AC代码:0ms*/
#include <iostream>
#include <cstdio>
#include <memory.h>
#include <algorithm>
#include <cmath>
#define min(a,b) (a<b?a:b)
#define PI 3.14159265358979323
#define eps 1e-7
using namespace std;
struct Node
{
	int x,y,r; 
	double m_area,br;
}node[30];
int N;
double map[30][30];
double ans;
double get_l(int a,int b)
{
	double x=node[a].x-node[b].x;
	double y=node[a].y-node[b].y;
	return sqrt(double(x*x+y*y));
}
void Init()
{
	int i,j;
	scanf("%d",&N);
	for(i=1;i<=N;i++)
	{
		scanf("%d%d%d",&node[i].x,&node[i].y,&node[i].r);
		node[i].m_area=(PI*node[i].r*node[i].r)/2.0;
		node[i].br=sqrt(node[i].m_area/PI);
	}
	for(i=1;i<=N;i++)
	{
		for(j=i+1;j<=N;j++)
		{
			map[i][j]=map[j][i]=get_l(i,j);
		}
	}
}
void swap(double &a,double &b)
{
	double t;
	if(a<b)
	{t=a;a=b;b=t;}
}
//求两圆的相交面(r1>r2,l为向圆心的距离)
double get_area(double r1,double r2,double l)
{
	double a1,a2,c1,c2,s1,s2;
	swap(r1,r2);
	if(l>=r1+r2) return 0;
	if(l<=fabs(r1-r2)) return PI*r2*r2;
	a2=(l*l+r2*r2-r1*r1)/(2*l);
	a1=l-a2;
	c1=2*acos(a1/r1);
	c2=2*acos(a2/r2);
	s1=r1*r1*c1/2-r1*r1*sin(c1)/2;
	s2=r2*r2*c2/2-r2*r2*sin(c2)/2;
	return s1+s2;
}
bool f(int ith,double mid,int a)
{
	double l=map[ith][a];
	double r1,r2;
	r1=mid;r2=node[a].r;
	if(r1<=r2) return false;
	if(r1-r2>=l) return true;
	double area=get_area(r1,r2,l);
	if((area-node[a].m_area)>eps) return true;
	return false; 
}
bool Judge(int ith,double mid)
{
	int i;
	bool ok=true;
	for(i=1;i<=N;i++)
	{
		if(i==ith) continue;
		if(!f(ith,mid,i))
		{ok=false;break;}
	}
	return ok;
}
void Run(int ith)
{
	double l,r,mid;
	l=node[ith].br;r=40000;
	while(fabs(r-l)>eps)
	{
		mid=(l+r)/2;
		if(Judge(ith,mid))
			r=mid;
		else
			l=mid; 
	}
	ans=min(ans,l);
}
void Solve()
{
	int i=1;
	ans=70000;
	for(i=1;i<=N;i++)
		Run(i);
	printf("%.4lf\n",ans);
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		Init();
		Solve();
	}
	return 0;
}

你可能感兴趣的:(HDU--3264[Open-air shopping malls] 枚举圆心+二分半径)