BZOJ1137:[POI2009]Wsp 岛屿(半平面交)

来源:互联网 发布:中秋节数据 编辑:程序博客网 时间:2024/05/17 23:22

传送门

Byteotia岛屿是一个凸多边形。城市全都在海岸上。按顺时针编号1到n。任意两个城市之间都有一条笔直的道路相连。道路相交处可以自由穿行。有一些道路被游击队控制了,不能走,但是可以经过这条道路与未被控制的道路的交点。问从城市1到n的最短距离。

题解:
首先凸多边形中1到n的最短路可以用半平面交做,发现一个点出发的直线只有可能是最后一条在半平面交中存在,所以用最后一条直接做半平面交就好了。

#include<bits/stdc++.h>using namespace std;inline int read(){    char ch=getchar();int i=0,f=1;    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}    while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}    return i*f;}const int Maxn=1e5+50;const double eps=1e-9;inline int sgn(double x){return (x>eps)-(x<-eps);}struct point{    double x,y;    point(){}    point(double x,double y):x(x),y(y){}    friend inline point operator -(const point &a,const point &b){return point(a.x-b.x,a.y-b.y);}    friend inline double operator *(const point &a,const point &b){return a.x*b.y-a.y*b.x;}    inline double norm(){return sqrt(x*x+y*y);}}p[Maxn];struct line{    point a,b;    double sp;    line(){}    line(point a,point b):a(a),b(b){}}l[Maxn];int n,m,tot;vector<int>ban[Maxn];inline bool operator <(const line &a,const line &b){    int t=sgn(a.sp-b.sp);    if(t)return t<0;    else return (b.b-a.a)*(b.a-a.a)>=0;}inline point insert(const line &a,const line &b){    double k1=(a.b-b.a)*(a.a-b.a);    double k2=(a.a-b.b)*(a.b-b.b);    #define t k1/(k1+k2)    return point(b.a.x+(b.b.x-b.a.x)*t,b.a.y+(b.b.y-b.a.y)*t);    #undef t}inline bool judge(const line &c,const line &a,const line &b){    point q=insert(a,b);    return (c.a-q)*(c.b-q)<eps; }inline void hpi(){    for(int i=1;i<=tot;i++)l[i].sp=atan2(l[i].b.y-l[i].a.y,l[i].b.x-l[i].a.x);    sort(l+1,l+tot+1);m=0;    for(int i=1;i<=tot;i++){        if(i==1||sgn(l[i].sp-l[i-1].sp))++m;        l[m]=l[i];    }    int L=1,R=2;    for(int i=3;i<=m;i++){        while(L<R&&judge(l[i],l[R-1],l[R]))--R;        while(L<R&&judge(l[i],l[L],l[L+1]))++L;        l[++R]=l[i];    }    while(L<R-1&&judge(l[R],l[L],l[L+1]))++L;    while(L<R-1&&judge(l[L],l[R-1],l[R]))--R;    double ans=-(p[n]-p[1]).norm();tot=0;l[++R]=l[L];    for(int i=L;i<R;++i)p[++tot]=insert(l[i],l[i+1]);    for(int i=1;i<tot;i++)ans+=(p[i+1]-p[i]).norm();    ans+=(p[1]-p[tot]).norm();    printf("%.10f\n",ans); }int main(){    n=read(),m=read();    for(int i=1;i<=n;i++)p[i].x=read(),p[i].y=read();    for(int i=1;i<=m;i++){        int x=read(),y=read();        ban[min(x,y)].push_back(max(x,y));    }    for(int i=1;i<=n;i++){        if(ban[i].size())sort(ban[i].begin(),ban[i].end());         int t=ban[i].size()-1,o=n;        while(t>=0&&ban[i][t]==o)--o,--t;        if(o>i)l[++tot]=line(p[o],p[i]);    }l[++tot]=line(p[1],p[n]);    hpi();} 
原创粉丝点击