HDU 4766 Network(计算几何 二分+三分)

来源:互联网 发布:新西兰留学 知乎 编辑:程序博客网 时间:2024/05/19 16:28

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4766

这个题目标准解法估计不是二分+三分,不过我一见到这个题目就认为是二分或者三分,所以一直想下去就写成了下面的代码,dubug好久才AC

二分枚举到房子的距离也就是路由器到房子的距离,然后三分判断在以房子为圆心这个距离为半径的的圆周上是否存在点能使这点到所有其他点

距离<r,这个三分判断利用圆的凸性很好判断,关键问题就是二分枚举距离的时候上下界无法确定,因为不具有单调性,但是如果能找到一点满足

题目条件,以这点为二分枚举的右端点,那么单调性就产生了。那么怎么找这个点呢,想起点集最小圆覆盖,求出圆心与半径(最小 是否存在问题

也解决了),最后二分!


#include <string.h>#include <stdio.h>#include <algorithm>#include <iostream>#include <math.h>using namespace std;#define MIN(a,b) (a<b?a:b)#define MAX(a,b) (a>b?a:b)#define inf 1e12#define eps 1e-8#define maxn 1500const double PI=acos(-1.0);struct point{    double x,y;    point(double _x=0,double _y=0):x(_x),y(_y){}}po[maxn],cir,temp,na;int n;double r,LL;double dis(point &a,point &b){    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}bool is_ok(){    double re=r*2,t=0,p;    point pp;    for(int i=1;i<=n;i++)    for(int j=i+1;j<=n;j++){        p=dis(po[i],po[j]);        if(p>t){            t=p;            pp=point((po[i].x+po[j].x)/2,(po[i].y+po[j].y)/2);            LL=dis(pp,cir);        }    }    if(t>re) return false;    return true;}int get_max_point(point &a){    int num=0,i;    double m=-1,re;    for(i=1;i<=n;i++){        re=dis(a,po[i]);        if(re>m) m=re,num=i;    }    return num;}bool solve(double left,double right,double R){//三分枚举    double ans,mid;    int num;    while(left<=right){        mid=(left+right)/2;        temp.x=cir.x+R*cos(mid);        temp.y=cir.y+R*sin(mid);        num=get_max_point(temp);        ans=dis(temp,po[num]);        if(ans<=r) return true;        mid+=eps;        temp.x=cir.x+R*cos(mid);        temp.y=cir.y+R*sin(mid);        mid-=eps;        if(dis(temp,po[num]) > ans)        right=mid-eps;        else left=mid+eps;    }    return false;}int find_ans(){    double left=0,right=LL,ans=LL,mid,th,th1,a,b;    int num,num1;    point t,t1;    while(left<=right){        mid=(left+right)/2;        if(solve(0,PI,mid) || solve(PI,PI*2,mid)) ans=MIN(ans,mid),right=mid-eps;        else left=mid+eps;    }    printf("%.2f\n",ans);    return 0;}#define MAXN 2000struct POINTSET{    double x, y;};const double precison=1.0e-8;POINTSET maxcic, point[MAXN];double radius;int curset[MAXN], posset[3];int set_cnt, pos_cnt;inline double dis_2(POINTSET &from, POINTSET& to){    return ((from.x-to.x)*(from.x-to.x)+(from.y-to.y)*(from.y-to.y));}int in_cic(int pt){    if(sqrt(dis_2(maxcic, point[pt]))<radius+precison) return 1;    return 0;}int cal_mincic(){    if(pos_cnt==1 || pos_cnt==0)        return 0;    else if(pos_cnt==3){        double A1, B1, C1, A2, B2, C2;        int t0=posset[0], t1=posset[1], t2=posset[2];        A1=2*(point[t1].x-point[t0].x);        B1=2*(point[t1].y-point[t0].y);        C1=point[t1].x*point[t1].x-point[t0].x*point[t0].x+            point[t1].y*point[t1].y-point[t0].y*point[t0].y;        A2=2*(point[t2].x-point[t0].x);        B2=2*(point[t2].y-point[t0].y);        C2=point[t2].x*point[t2].x-point[t0].x*point[t0].x+            point[t2].y*point[t2].y-point[t0].y*point[t0].y;        maxcic.y=(C1*A2-C2*A1)/(A2*B1-A1*B2);        maxcic.x=(C1*B2-C2*B1)/(A1*B2-A2*B1);        radius=sqrt(dis_2(maxcic, point[t0]));    }    else if(pos_cnt==2){        maxcic.x=(point[posset[0]].x+point[posset[1]].x)/2;        maxcic.y=(point[posset[0]].y+point[posset[1]].y)/2;        radius=sqrt(dis_2(point[posset[0]], point[posset[1]]))/2;    }    return 1;}int mindisk(){    if(set_cnt==0 || pos_cnt==3){        return cal_mincic();    }    int tt=curset[--set_cnt];    int res=mindisk();    set_cnt++;    if(!res || !in_cic(tt)){        set_cnt--;        posset[pos_cnt++]=curset[set_cnt];        res=mindisk();        pos_cnt--;        curset[set_cnt++]=curset[0];        curset[0]=tt;    }    return res;}int main1(int n){        int i;        for(i=0; i<n; i++)        point[i].x=po[i+1].x, point[i].y=po[i+1].y;            if(n==1){                maxcic.x=point[0].x;                maxcic.y=point[0].y;                radius=0;            }            set_cnt=n; pos_cnt=0;            for(i=0 ;i<n ;i++)  curset[i]=i;            mindisk();    return 0;}int main(){    int i,j,k;    while(scanf("%lf%lf%lf",&cir.x,&cir.y,&r)!=EOF){        scanf("%d",&n);        for(i=1;i<=n;i++) scanf("%lf%lf",&po[i].x,&po[i].y);        if(n==1){            printf("%.2lf\n",dis(cir,po[1])-r);            continue;        }        main1(n);        if(radius>r){            printf("X\n");continue;        }        na.x=maxcic.x,na.y=maxcic.y;        LL=dis(cir,na);        find_ans();    }    return 0;}


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 移动鼠标没反应怎么办 外出衣服皱了怎么办 画裤子上街私处怎么办 皮子背包掉颜色怎么办 gta5车子炸了怎么办 gta5钱多了怎么办 gta5技工不送车怎么办 考警察视力不行怎么办 警察经常熬夜该怎么办 武警部队中队长乱情怎么办 气动铆钉枪卡钉怎么办 汽车遥控器丢码怎么办 电表电池欠压怎么办 电表显示d0该怎么办 打印机打不出来怎么办 羽绒服内里跑绒怎么办 奥迪冷冻液不足怎么办 奥迪冷冻液报警怎么办 电脑输入时乱码怎么办 电信路由器坏了怎么办 高铁坐错车次了怎么办 数字万用表显示1怎么办 滚筒冼衣机接水接头漏水怎么办 奶块设备被禁封怎么办 奶块设备封禁怎么办 晚上衣服干不了怎么办 3dmax视图混乱怎么办 钉枪能打进肉里怎么办 公司迟发工资怎么办 打枪后一直耳鸣怎么办 打枪震的耳鸣怎么办 尚方宝剑弄丢了怎么办 九五出款被黑18w怎么办 很容易感动伤感哭怎么办 为什么安卓版ps打不开怎么办 遇见职业打假人怎么办 打假投诉极限次怎么办 导师无故留学生要怎么办 孩子24了不争气怎么办 退休工资卡遗失怎么办大同市 天津体育惠民卡怎么办