poj 3525 Most Distant Point from the Sea 半平面交 + 二分

来源:互联网 发布:宋朝生活知乎 编辑:程序博客网 时间:2024/06/15 03:13

题目来源:

http://poj.org/problem?id=3525

 

分析:
题意:给定一个凸多边形,求多边形中距离边界最远的点到边界的距离。
思路 : 每次将凸多边形每条边往里平移d,判断是否存在核;二分d即可。

多边形边上的点(x , y)往里平移d 后的 坐标: s , e  为向量的 起点和终点, len 为起点和终点的距离, h 为平移的距离

x' = x + dx 

y' = y + dy

dx = ( s.y - e.y ) / len * h ,( 原理 是 利用 三角形的相似比 )

dy = ( e.x - s.x  ) / len * h ;

 

代码如下:

 

using namespace std ;const double EPS = 1e-10 ;const int Max_N = 105 ;double add(double a, double b){    return (fabs(a + b) < EPS * (fabs(a) + fabs(b))) ? 0 : (a + b) ;}struct Point{    double x, y;    Point(){}    Point(double x, double y):x(x),y(y){}    Point operator - (Point a){        return Point(add(x , -a.x) , add(y , -a.y)) ;    }    Point operator + (Point a){        return Point(add(x ,a.x) , add(y , a.y)) ;    }    double operator ^(Point a){        return add(x * a.y , - y * a.x) ;    }    Point operator *(double d){        return Point(x * d, y * d) ;    }    double dist(Point a){        return sqrt( add((x - a.x) * (x - a.x) , (y - a.y)*(y - a.y) ) ) ;    }};struct Line{    Point st, ed;    Line(){}    Line(Point st, Point ed):st(st),ed(ed){}    bool onRight(Point a){ // 点在线右边        return ((ed - st)^(a - st)) < 0 ;    }    bool parallel(Line l){        return ((ed - st)^(l.ed - l.st)) == 0 ;    }    Point CrossNode(Line l){        double d1 = (l.ed - l.st)^(l.st - st) ;        double d2 = (l.ed - l.st)^(ed - st) ;        return st + (ed - st)*(d1 / d2) ;    }    double jijiao(){        return atan2(ed.y - st.y , ed.x - st.x) ;    }};bool operator < (Line l , Line r){    double lp = l.jijiao() ;    double rp = r.jijiao() ;    if(fabs(lp - rp) > EPS)        return lp < rp ;    return ((l.st - r.st)^(r.ed - r.st)) < 0 ;}Line dequeue[Max_N] ;int halfPanelCross(Line line[] , int ln){    int i, tn ;    sort(line , line + ln ) ;    for(i = tn = 1; i < ln ; i++){        if( fabs(line[i].jijiao() - line[i - 1].jijiao())  > EPS )            line[tn ++] = line[i] ;    }    ln = tn ;    int bot = 0 ,  top = 1 ;    dequeue[0] = line[0] ;    dequeue[1] = line[1] ;    Point topcross ,botcross ;    for(i = 2 ; i < ln  ; i++){        if(dequeue[top].parallel(dequeue[top - 1])   ||           dequeue[bot].parallel(dequeue[bot + 1]) )           return 0 ;        while(bot < top &&              line[i].onRight(topcross = dequeue[top].CrossNode(dequeue[top - 1])))              top -- ;        while(bot < top &&              line[i].onRight( botcross = dequeue[bot].CrossNode(dequeue[bot + 1])))              bot ++ ;        dequeue[++ top] = line[i] ;    }    while(bot < top &&          dequeue[bot].onRight(topcross = dequeue[top].CrossNode(dequeue[top - 1])))          top -- ;    while(bot < top &&          dequeue[top].onRight(botcross = dequeue[bot].CrossNode(dequeue[bot + 1])))          bot ++ ;    if(top <= bot + 1) return 0 ;    return 1;}Line tmp[Max_N] ;Line List[Max_N] ;void ploygonChange(double h, int ln){    double len , dx ,dy ;    for(int i= 0 ; i < ln ; i++){        len = List[i].ed.dist(List[i].st) ;        dx = (List[i].st.y - List[i].ed.y) / len * h ;        dy = (List[i].ed.x - List[i].st.x) / len * h ;        tmp[i].st.x = List[i].st.x + dx ;        tmp[i].st.y = List[i].st.y + dy ;        tmp[i].ed.x = List[i].ed.x + dx;        tmp[i].ed.y = List[i].ed.y + dy ;    }}double  BinSearch(int ln){    double l , r, mid ;    l = 0.0 , r = 20000.0 ;    while(l + EPS < r){        mid = (l + r) * 0.5 ;        ploygonChange(mid , ln ) ;        if(halfPanelCross(tmp , ln))            l = mid ;        else r = mid ;    }    return l;}int main(){    int n;    Point p[Max_N] ;    while(scanf("%d" , &n) && n){        for(int i = 0 ; i < n ; i++)            scanf("%lf%lf" , &p[i].x , &p[i].y) ;        for(int i = 0 ; i < n ; i++)            List[i] = Line(p[i] , p[(i+1) % n]) ;        double tt = BinSearch(n) ;        printf("%.6lf\n" ,tt) ;    }    return 0;}

 

0 0