题目来源:
http://acm.uestc.edu.cn/#/problem/show/814

题意:是给你一堆凸包上的点,这些点会形成一个凸多边形,有两个god站在这个多边形上,他们可以释放一个半径为r的魔法火圈,我们要求的就是两个god放出来的火圈完全覆盖这个多边形时的最小半径。

我的方法是二分半径,然后判断能否覆盖这个多边形是枚举每一条线段,判断每一条线段是否都能被一个圆,或者两个圆完全覆盖,如果能那么这个多边形就能完全被覆盖,只有有一条边不满足覆盖, 则这个多边形不能完全被覆盖。

其中判断一条跨两个圆的线段能否被两个圆完全覆盖时,用的二分,去找线段上是否存在一个点,同时在两个圆内,如果存在则这条线段能被两个圆完全覆盖。

代码如下:

#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <stdio.h>
#include <stack>
#include <string>
#include <string.h>
#include<cstring>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <set>
#include <math.h>
#include <cmath>
#include <map>
#include <queue>
using namespace std ;
typedef long long LL ;
const double EPS = 1e-10;
const int Max_N = 25;
double add(double x, double y){
    if (fabs(x+y) <  EPS*( fabs(x)+fabs(y)) )
        return 0;
    return x+y;
}
struct Point {
    double x,y;
    Point(){}
    Point(double x, double y):x(x),y(y){}
    double dist(Point p){
        return sqrt( (x-p.x)*(x-p.x) + (y-p.y)*(y-p.y) );
    }
};
Point p[Max_N];
Point mag[3];
int n;
// 跨圆的线段, 二分寻找是否存在一个点, 同时在2个圆内
int judge(Point l,Point r, Point ml, Point mr, double ra){
    Point mid;
    while( fabs(l.dist(r)) > EPS ){
        mid.x= (l.x + r.x) * 0.5;
        mid.y= (l.y + r.y) * 0.5;
        double d1=(ml.dist(mid) - ra);
        double d2=(mr.dist(mid) - ra);
        if(d1<=0 && d2<=0)
            return 1;
        if(d1 <= 0)
            l=mid;
        else
            r=mid;
    }
    return 0;
}
int judge1(double r){ // 枚举所有线段,看每条线段是否都能被覆盖
    int i,j;
    for(i=0; i<n-1; i++){
        for(j=i+1;j<n; j++){
            double r1,r2,r3,r4;
            r1=(p[i].dist(mag[1]) - r);
            r2=(p[j].dist(mag[1]) - r);
            r3=(p[i].dist(mag[2]) - r);
            r4=(p[j].dist(mag[2]) - r);
            if( (r1<= 0 && r2<= 0) || (r3<=0 && r4<=0) )
                continue;
            if( r1 <=0 && r4<=0 ){
                if(judge(p[i] ,p[j],mag[1],mag[2], r)) // judge判断一条跨线是否被覆盖
                    continue;
            }
            if(r2<=0 && r3<=0){
                if(judge( p[i],p[j],mag[2],mag[1],r ))
                    continue;
            }
            return 0;
        }
    }
    return 1;
}
int main(){
    while(~scanf("%d" ,&n)){
        for(int i=0; i<n; i++)
            scanf("%lf%lf",&p[i].x, &p[i].y );
        for(int i=1; i<=2; i++)
            scanf("%lf%lf",&mag[i].x, &mag[i].y);
        double ll=0.0, lr=4000.0; // lr不能开太小, 可以开大些
        double md;
        while(ll+ EPS <lr ){ //二分半径
            md=(ll + lr) * 0.5;
            if(judge1(md))
                lr=md;
            else
                ll=md;
        }
        printf("%.3lf\n",md);
    }
}