题目链接 :HDU 3264 Open-air shopping malls
题意:给出n个圆。要求一个在n个圆的圆心建一个大圆,使大圆与每一个小圆的交面积大于等于该小圆的面积的一般。求最小的大圆半径。
思路:二分大圆半径,枚举每个小圆与大圆的交面积。
注意精度问题。
AC代码:
#include <stdio.h>
#include <math.h>
#include <algorithm>
const double eps=1e-6;
const double PI=acos(-1.0);
using namespace std;
struct point
{
double x,y;
double r;
};
struct point p[30];
double dist(point a,point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double Area_of_overlap(point c1, double r1, point c2, double r2)
{
double d = dist(c1,c2);
if(r1 + r2 < d + eps) return 0;
if(d < fabs(r1 - r2) + eps)
{
double r = min(r1,r2);
return PI*r*r;
}
double x = (d*d + r1*r1 - r2*r2)/(2*d);
double t1 = acos(x / r1);
double t2 = acos((d - x)/r2);
return r1*r1*t1 + r2*r2*t2 - d*r1*sin(t1);
}
bool check(point p[],int n,point s,double r,int pos)
{
int i;
for(i=0; i<n; i++)
{
double area_s,area_p;
area_s=p[i].r*p[i].r*PI;//p[i]面积
area_p=Area_of_overlap(s,r,p[i],p[i].r);
if(area_s/2.0-area_p>eps)//没半圆
return true;
}
return false;
}
int main()
{
int t,i,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(i=0; i<n; i++)
scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].r);
double l,r,mid;
double minn=20100.0;
for(i=0; i<n; i++)
{
l=0,r=20100.0;
while((r-l)>eps)
{
mid=(l+r)/2.0;
if(check(p,n,p[i],mid,i))
l=mid+eps;
else
r=mid-eps;
}
minn=min(minn,l);
}
printf("%.4lf\n",minn);
}
return 0;
}
/*
3
5
0 0 1
2 0 1
0 2 1
-2 0 1
0 -2 1
2
0 0 1
2 0 1
1
0 0 1
*/