procedure2012
It's not worth it to know you're not worth it!

[关键字]:数学 计算几何

[题目大意]:给出若干个互相分离的园,要求找到一个最小的半径使得每个圆都被以这个为半径以给出的某个圆圆心为圆心的圆覆盖至少一半。

//============================================================================================================================

[分析]:首先枚举每个圆的圆心作为圆心,在二分半径并判断是否符合要求。这样找出每个圆为圆心的半径的最小值,问题就在与怎样判断是否符合要求。相离、外切、内切、内含都好判断,但是相交情况怎样判断面积?传送门:http://www.cnblogs.com/evan-oi/archive/2012/03/14/2395989.html

[代码]:

View Code
#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cstdlib>

#include<cmath>

using namespace std;



const int MAXN=1000;

const double ZERO=1e-8;

const double PI=3.1415926535;

const double EJ=1e-6;



int n;

double x[MAXN],y[MAXN],r[MAXN];



void Init()

{

scanf("%d",&n);

for (int i=1;i<=n;++i)

scanf("%llf%llf%llf",&x[i],&y[i],&r[i]);

}



double Find(double a,double b,double c)

{

double ar=acos((a*a+b*b-c*c)/(2*a*b))*2;

double s1=a*a*ar/2;

double s2=a*a*sin(ar)/2;

return s1-s2;

}



bool Judge(double x0,double y0,double r0,double x1,double y1,double r1)

{

double d=sqrt((x0-x1)*(x0-x1)+(y0-y1)*(y0-y1));

if (d+ZERO>=r0+r1) return 0;

if (d-ZERO<=fabs(r0-r1))

{

if (r0>r1)

return 1;

else

if (r0*r0*2+ZERO>=r1*r1) return 1; else return 0;

}

double temp=Find(r0,d,r1)+Find(r1,d,r0);

if (temp*2>=r1*r1*PI) return 1; else return 0;

}



bool Cleck(double x0,double y0,double r0)

{

for (int i=1;i<=n;++i)

if (!Judge(x0,y0,r0,x[i],y[i],r[i])) return 0;

return 1;

}



double Calc(double x0,double y0)

{

double l=0,r=1e6,ans;

while (r-l>EJ)

{

double mid=(l+r)/2.0;

if (Cleck(x0,y0,mid)) ans=mid,r=mid; else l=mid;

}

return ans;

}



void Solve()

{

double ans=1e10;

for (int i=1;i<=n;++i)

{

double temp=Calc(x[i],y[i]);

if (temp<ans) ans=temp;

}

printf("%.4llf\n",ans);

}



int main()

{

int test;

scanf("%d",&test);

while (test--)

{

Init();

Solve();

}

system("pause");

return 0;

}



posted on 2012-03-15 07:40  procedure2012  阅读(274)  评论(0编辑  收藏  举报