题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3264
题意:
给定n个圆的圆心和半径,求一个圆心为这些圆中任意一个,与所有圆相交的面积超过其面积一半的圆的最小半径。
分析:
枚举圆心,然后二分得到最小的半径,直接套求圆交的模板。
代码如下:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
const double eps = 1e-8;
const double pi = acos(-1.0);
int n;
struct point
{
double x,y,r;
}cir[25];
double S(point a)
{
return pi*a.r*a.r;
}
double dis(point a,point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double calu(point a,point b)
{
point tmpa=a,tmpb=b;
if(tmpa.r<tmpb.r) swap(tmpa,tmpb);
double area = 0;
double dd = dis(tmpa,tmpb);
if(dd>tmpa.r-tmpb.r&&dd<tmpa.r+tmpb.r){
double cos1 = (tmpa.r*tmpa.r+dd*dd-tmpb.r*tmpb.r)/(2*tmpa.r*dd);
double cos2 = (tmpb.r*tmpb.r+dd*dd-tmpa.r*tmpa.r)/(2*tmpb.r*dd);
double th1 = 2*acos(cos1);
double th2 = 2*acos(cos2);
double s1 = 0.5*tmpa.r*tmpa.r*sin(th1);
double s2 = 0.5*tmpb.r*tmpb.r*sin(th2);
double s3 = (th1/2)*tmpa.r*tmpa.r;
double s4 = (th2/2)*tmpb.r*tmpb.r;
area = s3+s4-s1-s2;
}
else if(dd<=tmpa.r-tmpb.r)
area = S(tmpb);
return area;
}
bool check(point a)
{
for(int i=0;i<n;i++){
if(calu(a,cir[i])*2<pi*cir[i].r*cir[i].r)
return false;
}
return true;
}
double bin_search(double l,double r,point tmp)
{
double mid;
while(r-l>=eps){
mid=(l+r)/2.0;
tmp.r=mid;
if(check(tmp)) r=mid;
else l=mid+eps;
}
return mid;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%lf%lf%lf",&cir[i].x,&cir[i].y,&cir[i].r);
point ans;
double r=1000000;
for(int i=0;i<n;i++){
ans.x=cir[i].x,ans.y=cir[i].y;
r=min(r,bin_search(0,30000,ans));
}
printf("%.4lf\n",r);
}
return 0;
}
HDU3264 Open-air shopping malls (圆交+二分)
原文:http://blog.csdn.net/bigbigship/article/details/41865911