POJ 3525 Most Distant Point from the Sea

来源:互联网 发布:社交媒体数据分析 编辑:程序博客网 时间:2024/06/05 16:52

2016暑期集训6-E

POJ 3525 Most Distant Point from the Sea

半平面交,二分

传送门:POJ

传送门:HustOJ


题意

(0,0)开始,逆时针给出一些点,这些点构成一个凸多边形,求多边形内离边界最远的距离。


思路

  • 就是二分答案在求半平面交。

  • 具体说半平面交,就是给你一堆直线,他们的左边表示有效区域,求所有有效区域的交集(这里模板是返回一组边界点),类似于线性规划的可行域。

  • 所以这题,把直线逆时针组成一个多边形,每条直线左边就是有效区域。二分答案,如果每条直线同时向它的左侧(多边形内测)平移x,那么最远点到边界的距离也减小x,如果半平面交的点集为空,说明平移的x过大。这样二分就行了。


代码

感谢kuangbin大佬的模板

#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>#include <vector>#include <queue>#include <set>#include <map>#include <string>#include <math.h>#include <stdlib.h>#include <time.h>using namespace std;const double eps=1e-8;const double PI=acos(-1.0);const int MAXN=107;int sgn(double x)//符号函数{    if(fabs(x) < eps) return 0;    if(x < 0) return -1;    else return 1;}//点,向量struct Point{    double x,y;    Point(){}    Point(double _x,double _y)//构造    {        x=_x; y=_y;    }    Point operator -(const Point &b)const    {        return Point(x-b.x,y-b.y);    }    double operator ^(const Point &b)const//叉积    {        return x*b.y-y*b.x;    }    double operator *(const Point &b)const//点积    {        return x*b.x+y*b.y;    }};//线struct Line{    Point s,e;//两点    double k;//斜率    Line(){}    Line(Point _s,Point _e)//构造    {        s=_s; e=_e;        k=atan2(e.y-s.y,e.x-s.x);    }    Point operator &(const Line &b)const//求两直线交点    {        Point res=s;        double t=((s-b.s)^(b.s-b.e))/((s-e)^(b.s-b.e));        res.x+=(e.x-s.x)*t;        res.y+=(e.y-s.y)*t;        return res;    }};Line Q[MAXN];Point p[MAXN];//记录最初给的点集Line line[MAXN];//由最初的点集生成直线的集合Point pp[MAXN];//记录半平面交的结果的点集//半平面交,直线的左边代表有效区域//直线排序函数bool HPIcmp(Line a,Line b){    //斜率排序    if(fabs(a.k-b.k) > eps)return a.k < b.k;    //斜率相同我也不知道怎么办    return ((a.s-b.s)^(b.e-b.s)) < 0;}//line是半平面交的直线的集合 n是直线的条数 res是结果的点集 resn是点击里面点的个数void HPI(Line line[],int n,Point res[],int &resn){    int tot=n;    sort(line,line+n,HPIcmp);    tot=1;    for(int i=1;i < n;i++)        if(fabs(line[i].k-line[i-1].k) > eps)//去掉斜率重复的            line[tot++]=line[i];    int head=0,tail=1;    Q[0]=line[0];    Q[1]=line[1];    resn=0;    for(int i=2; i < tot; i++)    {        if(fabs((Q[tail].e-Q[tail].s)^(Q[tail-1].e-Q[tail-1].s)) < eps||fabs((Q[head].e-Q[head].s)^(Q[head+1].e-Q[head+1].s)) < eps)            return;        while(head < tail&&(((Q[tail]&Q[tail-1])-line[i].s)^(line[i].e-line[i].s)) > eps)            tail--;        while(head < tail&&(((Q[head]&Q[head+1])-line[i].s)^(line[i].e-line[i].s)) > eps)            head++;        Q[++tail]=line[i];    }    while(head < tail&&(((Q[tail]&Q[tail-1])-Q[head].s)^(Q[head].e-Q[head].s)) > eps)        tail--;    while(head < tail&&(((Q[head]&Q[head-1])-Q[tail].s)^(Q[tail].e-Q[tail].e)) > eps)        head++;    if(tail<=head+1)return;    for(int i=head; i < tail; i++)        res[resn++]=Q[i]&Q[i+1];    if(head < tail-1)        res[resn++]=Q[head]&Q[tail];}double dist(Point a,Point b)//两点间距离{    return sqrt((a-b)*(a-b));}//将线段ab往左移动距离p,修改得到线段cdvoid change(Point a,Point b,Point &c,Point &d,double p){    double len=dist(a,b);    /*三角形相似推出下面公式*/    double dx=(a.y-b.y)*p/len;    double dy=(b.x-a.x)*p/len;    c.x=a.x+dx; c.y=a.y+dy;    d.x=b.x+dx; d.y=b.y+dy;}int main(){    int n;    while(~scanf("%d",&n)&&n!=0)    {        memset(Q,0,sizeof(Q));        memset(p,0,sizeof(p));        memset(pp,0,sizeof(pp));        memset(line,0,sizeof(line));        for(int i=0;i < n;i++)            scanf("%lf%lf",&p[i].x,&p[i].y);        double l=0,r=100000;        double ans=0;        while(r-l>=eps)        {            double mid=(l+r)/2;            for(int i=0;i < n;i++)            {                Point t1,t2;                change(p[i],p[(i+1)%n],t1,t2,mid);                line[i]=Line(t1,t2);            }            int resn;            HPI(line,n,pp,resn);            //二分            if(resn==0)//等于0说明移多了                r=mid-eps;            else            {                ans=mid;                l=mid+eps;            }        }        printf("%.6f\n",ans);    }    return 0;}
0 0