zoukankan      html  css  js  c++  java
  • [bzoj1020][SHOI2008]安全的航线flight【迭代】【计算几何】

    【题目链接】
      http://www.lydsy.com/JudgeOnline/problem.php?id=1020
    【题解】
      首先有一个朴素的想法就是二分,然后判断带圆弧的多边形是否能完全覆盖直线,是不是很简单?
      但我不会 QAQ
      考虑暴力枚举每一个点(隔0.005),求出它到最近陆地的距离,取最大值。
      这样做编程复杂度会下降很多,但会 TLE。
      观察后发现,许多状态是多余的,于是想到剪枝,具体的方法是:
        1.将每一条线段加入队列中。
        2.区出队收线段,找出线段两端的最近点,二分找出距离这两个点最远的在线段上点,设为 mid,若它到这两个点的最近距离 当前答案,就将整个线段删除。
        tips:找 mid 时,它要么在线段最左边,要么在最右边,要么在垂直平分线上,所以二分垂直平分线(直接求也行),然后与左右比较。
        3.用 mid 更新答案。
        4.加入左端点到 midmid 到右端点的线段。(满足长度≥0.005)
        5.重复2-4直到队列为空。
      这种做法能顺利通过此题,复杂度 O(???)
      还是挺好(nan)写的

    /* --------------
        user Vanisher
        problem bzoj-1020 
    ----------------*/
    # include <bits/stdc++.h>
    # define    ll      long long
    # define    inf     1e9
    # define    eps     1e-4
    # define    anseps  1e-3
    # define    N       110
    # define    T       5000000
    using namespace std;
    int num[N],n,m,k;
    struct point{
        double x,y;
    }mp[N][N],rd[N];
    struct seg{
        point a,b;
    }l[N*N],q[T];
    double ans;
    point operator +(point x, point y){return (point){x.x+y.x,x.y+y.y};}
    point operator -(point x, point y){return (point){x.x-y.x,x.y-y.y};}
    point operator *(point x, double y){return (point){x.x*y,x.y*y};}
    point operator /(point x, double y){return (point){x.x/y,x.y/y};}
    double sqr(double x){return x*x;}
    double dis(point x, point y){
        return sqrt(sqr(x.x-y.x)+sqr(x.y-y.y));
    }
    double dot(point x, point y){
        return x.x*y.x+x.y*y.y;
    }
    double cross(point x, point y){
        return x.x*y.y-x.y*y.x;
    }
    double dis_PtoS(point x, seg y){
        if (dot(x-y.a,y.b-y.a)<0) return dis(x,y.a);
        if (dot(x-y.b,y.a-y.b)<0) return dis(x,y.b);
        return fabs(cross(y.a-x,y.b-x))/dis(y.a,y.b);
    }
    point PtoS(point x, seg y){
        if (dot(x-y.a,y.b-y.a)<0) return y.a;
        if (dot(x-y.b,y.a-y.b)<0) return y.b;
        double d=dis_PtoS(x,y), d1=sqrt(sqr(dis(y.a,x))-sqr(d));
        return y.a+(y.b-y.a)*(d1/dis(y.a,y.b));
    }
    bool PonS(point x, seg y){
        return fabs(cross(x-y.a,x-y.b))<eps&&dot(x-y.a,x-y.b)<eps;
    }
    bool ScrossS(seg a, seg b){
        return cross(a.a-b.a,b.b-b.a)*cross(a.b-b.a,b.b-b.a)<eps&&cross(b.a-a.a,a.b-a.a)*cross(b.b-a.a,a.b-a.a)<eps;
    }
    bool in(point x, int id){
        for (int i=1; i<=num[id]; i++)
            if (PonS(x,(seg){mp[id][i],mp[id][i+1]})==true) 
                return true;
        point y={10001,x.y+0.1}; int cnt=0;
        for (int i=1; i<=num[id]; i++)
            if (ScrossS((seg){x,y},(seg){mp[id][i],mp[id][i+1]})==true) cnt++;
        return cnt%2;
    }
    
    int read(){
        int tmp=0, fh=1; char ch=getchar();
        while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
        while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
        return tmp*fh;
    }
    
    bool check(point x){
        bool now=false;
        for (int i=1; i<=m; i++){
            now=now|in(x,i);
        }
        return now;
    }
    point findnear(point x){
        if (check(x)) return x;
        point mn={inf,inf};
        for (int i=1; i<=k; i++){
            point now=PtoS(x,l[i]);
            if (dis(mn,x)>dis(now,x)) mn=now;
        }
        return mn;
    } 
    void checkans(point x){
        point y=findnear(x);
        ans=max(ans,dis(x,y));
    }
    int main(){
        m=read(), n=read();
        for (int i=1; i<=n; i++)
            rd[i].x=read(), rd[i].y=read(); 
        for (int i=1; i<=m; i++){
            num[i]=read();
            for (int j=1; j<=num[i]; j++)
                mp[i][j].x=read(), mp[i][j].y=read();
            mp[i][num[i]+1]=mp[i][1];
            for (int j=1; j<num[i]; j++)
                l[++k].a=mp[i][j], l[k].b=mp[i][j+1];
            l[++k].a=mp[i][num[i]], l[k].b=mp[i][1];
        }
        int pl=1, pr=0;
        for (int i=1; i<n; i++)
            q[++pr].a=rd[i],q[pr].b=rd[i+1];
        while (pl<=pr){
            seg now=q[pl++];
            point lp=findnear(now.a), rp=findnear(now.b), l=now.a, r=now.b, mid;
            while (dis(l,r)>anseps){
                mid=(l+r)/2;
                if (dis(mid,lp)>dis(mid,rp)) 
                    r=mid; else l=mid;
            }
            checkans(now.a); checkans(now.b); checkans(mid);
            if (dis(mid,lp)<ans+eps) continue; 
            if (dis(now.a,mid)>anseps) q[++pr].a=now.a, q[pr].b=mid;
            if (dis(mid,now.b)>anseps) q[++pr].a=mid, q[pr].b=now.b;
        }
        printf("%.2lf
    ",ans);
        return 0;
    }
  • 相关阅读:
    javascript获取id元素
    小米供应链
    几个极限的证明
    第一章 实数
    当a在什么范围取值时,方程|x方-5x|=a有且只有两个相异实根
    壮壮的西城学探究里面的x=1,x=-1
    三角形的边长注意问题
    x方+x+1, x方-x+1无实根,不可能为0
    一个混合电路
    串联电路的电流处处相等
  • 原文地址:https://www.cnblogs.com/Vanisher/p/9136003.html
Copyright © 2011-2022 走看看