BZOJ 1137: [POI2009]Wsp 岛屿【半平面交】

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/C20181220_xiang_m_y/article/details/88973659

题面:

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

题目分析:

看到题的第一眼:最短路??
一搜题解,半平面交,???
然后再仔细看题面。。“凸多边形”,“顺时针编号”,“道路相交处可以自由穿行”。
哦,半平面交。

因为是求1到n的最短路,所以一个点只需要用与它相连的编号最大的点的那条边做半平面交就可以了。
放一个半平面交的学习地址,讲得挺好的:半平面交算法入门详解
还有两条线怎么求交点,有一个几何算法,比较好记:Oi-wiki二维计算几何基础

Code:

#include<cstdio>
#include<cmath>
#include<vector>
#include<cctype>
#include<algorithm>
#define maxn 100005
using namespace std;
const double eps = 1e-8;
template<class T>inline void read(T &a){
    char c;bool f=0;while(!isdigit(c=getchar())) if(c=='-') f=1;
    for(a=c-'0';isdigit(c=getchar());a=a*10+c-'0'); if(f) a=-a;
}
struct Point{
    double x,y; Point(){}
    Point(double x,double y):x(x),y(y){}
    Point operator + (const Point &p){return Point(x+p.x,y+p.y);}
    Point operator - (const Point &p){return Point(x-p.x,y-p.y);}
    Point operator * (const double &t){return Point(x*t,y*t);}
    double operator * (const Point &b){return x*b.y-y*b.x;}
}p[maxn],a[maxn];
struct Line{
    Point p,v;
    double ang; Line(){}
    Line(Point a,Point b){p=a,v=b-a,ang=atan2(v.y,v.x);}
}L[maxn],q[maxn];

inline double sqr(double x){return x*x;}
inline int dcmp(double x){return fabs(x)<eps?0:x>0?1:-1;}
inline bool Onleft(Line a,Point b){return a.v*(b-a.p)>0;}
inline double dist(Point a,Point b){return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));}
inline Point GetInt(Line a,Line b){
    double t = (b.v*(a.p-b.p))/(a.v*b.v);
    return a.p+a.v*t;
}
inline bool cmp(const Line &a,const Line &b){
    if(dcmp(a.ang-b.ang)==0) return Onleft(b,a.p);
    return a.ang<b.ang;
}

int n,m,cnt;
double ans;
vector<int>e[maxn];
void HalfPlane(){
    sort(L+1,L+1+cnt,cmp);
    int l,r;
    q[l=r=1]=L[1];
    for(int i=2;i<=cnt;i++) if(dcmp(L[i].ang-L[i-1].ang)){
        while(l<r&&!Onleft(L[i],p[r-1])) r--;
        while(l<r&&!Onleft(L[i],p[l])) l++;
        q[++r]=L[i];
        p[r-1]=GetInt(q[r-1],q[r]);
    }
    while(l<r&&!Onleft(q[l],p[r-1])) r--;
    if(r-l<=1) {printf("%.9f",dist(a[1],a[n]));return;}
    p[r]=GetInt(q[l],q[r]);
    for(int i=l;i<r;i++) ans+=dist(p[i],p[i+1]);
    ans+=dist(p[r],p[l])-dist(a[1],a[n]);
    printf("%.9f",ans);
}
int main()
{
    int x,y;
    read(n),read(m);
    for(int i=1;i<=n;i++) read(a[i].x),read(a[i].y);
    while(m--) read(x),read(y),e[min(x,y)].push_back(max(x,y));
    for(int i=1,j;i<n;i++){
        sort(e[i].begin(),e[i].end());
        j=n;while(!e[i].empty()&&e[i].back()==j) j--,e[i].pop_back();
        if(i==1&&j==n) return printf("%.9f\n",dist(a[1],a[n])),0;
        if(j>i) L[++cnt]=Line(a[j],a[i]);
    }
    L[++cnt]=Line(a[1],a[n]);
    HalfPlane();
}

又开始犯傻逼错误。。最后的ans+=p[r]-p[l]写成p[r]-p[1]。。

猜你喜欢

转载自blog.csdn.net/C20181220_xiang_m_y/article/details/88973659