• 小学半平面交


    快到省选了,赶紧学一发计算几何……
    这玩意就是线性规划.
    半平面通常用不等式或者两点表示,具体表示方法,就题而言,要灵活.
    算法的话,什么朴素O(n^2),什么分治,都不会,只会一个弹栈的.
    这个算法的话,一开始好像一定要去重,而且有的时候需要在外面加4个框,似乎是因为这个算法在相邻直线的极角跨度大于Pi的时候就不对了……似乎还是为了保证判断无解的方法(剩余直线小于3个)的正确性……
    反正我就大概懂一些计算几何基础(向量啊什么的),并且感性理解了一发这个算法……
    就做了几道水题:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    const int N=10010;
    struct Race{
        double k,b;
        int id;
    }race[N],stack[N];
    int top;
    inline bool comp(Race a,Race b){
        return a.k<b.k||(a.k==b.k&&a.b>b.b);
    }
    int n;
    bool good[N];
    inline void Init(){
        scanf("%d",&n);
        int i;
        for(i=1;i<=n;++i)
            scanf("%lf",&race[i].b);
        for(i=1;i<=n;++i)
            scanf("%lf",&race[i].k),race[i].id=i;
    }
    inline bool check(Race a,Race b,Race c){
        double x=(double)(b.b-a.b)/(a.k-b.k);
        double y=a.k*x+a.b;
        return y>=c.k*x+c.b;
    }
    inline void Work(){
        int i,j;
        std::sort(race+1,race+(n+1),comp);
        j=0;
        race[++j]=race[1];
        for(i=2;i<=n;++i)
            if(race[i].k!=race[j].k||(race[i].k==race[j].k&&race[i].b==race[j].b))
                race[++j]=race[i];
        stack[++top]=(Race){1./0.,0.,0};
        for(i=1;i<=j;++i){
            while(top>1&&!check(stack[top],stack[top-1],race[i]))--top;
            stack[++top]=race[i];
        }
    }
    inline void Print(){
        int i;
        for(i=1;i<=top;++i)
            good[stack[i].id]=true;
        printf("%d
    ",top-1);
        for(i=1;i<=n;++i)
            if(good[i])
                printf("%d ",i);
        puts("");
    }
    int main(){
        Init(),Work(),Print();
        return 0;
    }
    bzoj3190:[JLOI2013]赛车
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    const int N=110;
    const double oo=1e10;
    const double eps=1e-6;
    int n;
    double s;
    struct Peo{
        double k,b;
        inline void redef(double x,double y){
            k=1./x-1./y;
            b=s/y;
        }
        inline double query(double pos){
            return k*pos+b;
        }
    }peo[N];
    inline double query(double pos){
        double ret=oo;
        for(int i=1;i<n;++i)
            ret=std::min(ret,peo[i].query(pos));
        ret-=peo[n].query(pos);
        return ret;
    }
    int main(){
        scanf("%lf%d",&s,&n);
        int i;
        double l,r,mid1,mid2,x,y,ans1=0.,ans2=-oo;
        for(i=1;i<=n;++i){
            scanf("%lf%lf",&x,&y);
            x/=3600,y/=3600;
            peo[i].redef(x,y);
        }
        l=0.,r=s;
        while(l+eps<r){
            mid1=(r-l)/3+l;
            mid2=r-(r-l)/3;
            x=query(mid1);
            y=query(mid2);
            if(x<=y)
                ans2=y,ans1=mid2,l=mid1;
            else
                ans2=x,ans1=mid1,r=mid2;
        }
        x=query(0);
        if(x>=ans2)ans2=x,ans1=0;
        if(ans2<0)puts("NO");
        else printf("%.2f %.2f %.0f
    ",ans1,s-ans1,ans2);
        return 0;
    }
    bzoj2765:[JLOI2010]铁人双项比赛
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    const int N=310;
    const double oo=1e10;
    const double eps=1e-8;
    struct Poi{
        double x,y;
        inline friend double operator *(Poi a,Poi b){
            return a.x*b.y-a.y*b.x;
        }
        inline friend Poi operator -(Poi a,Poi b){
            return (Poi){a.x-b.x,a.y-b.y};
        }
    }dia[N];
    struct Line{
        Poi s,t;
        double k;
        inline void redef(Poi a,Poi b){
            s=a,t=b,k=std::atan2(b.y-a.y,b.x-a.x);
        }
    }line[N],stack[N];
    int top;
    inline bool comp(Line a,Line b){
        return a.k==b.k?(b.s-a.s)*(b.t-a.s)>0:a.k<b.k;
    }
    int n;
    inline Poi point(Line a,Line b){
        Poi ret;
        double s1=(b.s-a.s)*(b.t-a.s);
        double s2=(b.t-a.t)*(b.s-a.t);
        ret.x=(s1*a.t.x+s2*a.s.x)/(s1+s2);
        ret.y=(s1*a.t.y+s2*a.s.y)/(s1+s2);
        return ret;
    }
    inline bool check(Line a,Line b,Line c){
        Poi poi=point(a,b);
        return (c.s-poi)*(c.t-poi)>0;
    }
    inline void Init(){
        scanf("%d",&n);
        int i;
        for(i=1;i<=n;++i)
            scanf("%lf",&dia[i].x);
        for(i=1;i<=n;++i)
            scanf("%lf",&dia[i].y);
        dia[0]=(Poi){dia[1].x,oo};
        dia[n+1]=(Poi){dia[n].x,oo};
        ++n;
        for(i=1;i<=n;++i)
            line[i].redef(dia[i-1],dia[i]);
    }
    inline void Work(){
        std::sort(line+1,line+(n+1),comp);
        int i,j;
        j=0;
        line[++j]=line[1];
        for(i=2;i<=n;++i)
            if(line[i].k!=line[j].k)
                line[++j]=line[i];
        stack[++top]=line[1];
        stack[++top]=line[2];
        for(i=3;i<=j;++i){
            while(top>1&&!check(stack[top],stack[top-1],line[i]))--top;
            stack[++top]=line[i];
        }
    }
    inline double query(double pos){
        Poi p1=(Poi){pos,0},p2=(Poi){pos,oo},poi;
        Line tmp;
        tmp.redef(p1,p2);
        double ret=-oo;
        for(int i=2;i<top;++i){
            poi=point(tmp,stack[i]);
            ret=std::max(ret,poi.y);
        }
        return ret;
    }
    inline void Print(){
        int i,at;
        double ans=oo;
        Poi poi;
        for(i=1;i<n;++i)
            ans=std::min(ans,query(dia[i].x)-dia[i].y);
        at=1;
        for(i=3;i<top;++i){
            poi=point(stack[i-1],stack[i]);
            while(poi.x>=dia[at+1].x)++at;
            ans=std::min(ans,poi.y-((dia[at+1].y-dia[at].y)*(poi.x-dia[at].x)/(dia[at+1].x-dia[at].x)+dia[at].y));
        }
        printf("%.3f
    ",ans);
    }
    int main(){
        //freopen("rio.txt","r",stdin);
        //freopen("wq.txt","w",stdout);
        Init(),Work(),Print();
        return 0;
    }
    bzoj1038:[ZJOI2008]瞭望塔
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    const int N=110;
    double s=1;
    int n,v[N],u[N],w[N];
    struct Line{
        double a,b,c,k;
        inline void redef(double x,double y,double z){
            a=x,b=y,c=z;
            if(x<0)x=-x;
            if(x)a/=x,b/=x,c/=x;
            k=std::atan2(-a,b);
        }
    }line[N],queue[N];
    int head,tail;
    inline bool comp(Line a,Line b){
        return a.k!=b.k?a.k<b.k:a.c<b.c;
    }
    inline bool check(Line a,Line b,Line c){
        double x=(b.c*a.b-a.c*b.b)/(a.a*b.b-a.b*b.a);
        double y=(b.c*a.a-a.c*b.a)/(a.b*b.a-a.a*b.b);
        return c.a*x+c.b*y+c.c>0;
    }
    inline void Init(){
        scanf("%d",&n);
        int i;
        for(i=1;i<=n;++i)
            scanf("%d%d%d",&v[i],&u[i],&w[i]);
    }
    inline bool check(int id){
        int m=5,i,j;
        line[1].redef(1,0,0);
        line[2].redef(-1,0,s);
        line[3].redef(0,1,0);
        line[4].redef(0,-1,s);
        line[5].redef(-1,-1,s);
        double a,b,c;
        for(i=1;i<=n;++i){
            if(i==id)continue;
            if(v[id]<=v[i]&&u[id]<=u[i]&&w[id]<=w[i])return false;
            a=1./v[id]-1./v[i];
            b=1./u[id]-1./u[i];
            c=1./w[id]-1./w[i];
            ++m;
            line[m].redef(c-a,c-b,-c*s);
        }
        std::sort(line+1,line+(m+1),comp);
        j=0;
        line[++j]=line[1];
        for(i=2;i<=m;++i)
            if(line[i].k!=line[j].k)
                line[++j]=line[i];
        head=tail=0;
        queue[tail++]=line[1];
        queue[tail++]=line[2];
        for(i=3;i<=j;++i){
            while(tail-head>1&&!check(queue[tail-1],queue[tail-2],line[i]))--tail;
            while(tail-head>1&&!check(queue[head],queue[head+1],line[i]))++head;
            queue[tail++]=line[i];
        }
        while(tail-head>1&&!check(queue[tail-1],queue[tail-2],queue[head]))--tail;
        return tail-head>2;
    }
    inline void Print(){
        int i;
        for(i=1;i<=n;++i)
            puts(check(i)?"Yes":"No");
    }
    int main(){
        Init();Print();
        return 0;
    }
    bzoj3800:Saber VS Lancer
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    const int N=100010;
    const double oo=1e20;
    int n,cnt;
    struct Line{
        double a,b,c,k;
        int id;
        inline void redef(double x,double y,double z,int name){
        //如果x、y都为0,那么若z>=0成立,则整张图都成立,若不成立,则整张图都不成立
            id=name;
            a=x,b=y,c=z;
            if(x<0)x=-x;
            if(x)a/=x,b/=x,c/=x;
            else{
                if(y<0)y=-y;
                if(y)a/=y,b/=y,c/=y;
            }
            k=std::atan2(-a,b);
        //讨论一下4种平行、外加Delta的计算,就会发现这是对的 
        }
    }keep[N<<1],line[N<<1],queue[N<<1];
    int head,tail;
    inline bool comp(Line a,Line b){
        return a.k!=b.k?a.k<b.k:a.c<b.c;
        //在我们上面进行了除x且除y的操作之后,这样是对的 
    }
    inline bool check(Line a,Line b,Line c){
        double x=(a.b*b.c-b.b*a.c)/(b.b*a.a-a.b*b.a);
        double y=(a.a*b.c-b.a*a.c)/(b.a*a.b-a.a*b.b);
        return c.a*x+c.b*y+c.c>=0;
        //手推一下就能出来,只要记住x的主料为b、y的主料为a、上下主料相反、单项相反、上c下反即可 
    } 
    inline bool check(int k){
        int i,j=0;
        for(i=1;i<=cnt;++i)
            if(keep[i].id<=k&&(j==0||keep[i].k!=line[j].k))
                line[++j]=keep[i];
        head=tail=0;
        queue[tail++]=line[1];
        queue[tail++]=line[2];
        for(i=3;i<=j;++i){
            while(tail-head>1&&!check(queue[tail-1],queue[tail-2],line[i]))--tail;
            while(tail-head>1&&!check(queue[head],queue[head+1],line[i]))++head;
            queue[tail++]=line[i];
        }
        while(tail-head>1&&!check(queue[tail-1],queue[tail-2],queue[head]))--tail;
        return tail-head>=3;
    }
    inline void Init(){
        cnt=4;
        keep[1].redef(1,0,oo,0);
        keep[2].redef(-1,0,0,0);
        keep[3].redef(0,1,oo,0);
        keep[4].redef(0,-1,oo,0);
        scanf("%d",&n);
        int i,j,x,y,z;
        for(i=1;i<=n;++i){
            scanf("%d%d%d",&x,&y,&z);
            keep[++cnt].redef((double)x*x,x,-y,i);
            keep[++cnt].redef(-(double)x*x,-x,z,i);
        }
        std::sort(keep+1,keep+(cnt+1),comp);
    }
    inline void Work(){
        int l=1,r=n,mid,ans=0;
        while(l<=r){
            mid=(l+r)>>1;
            if(check(mid))
                ans=mid,l=mid+1;
            else
                r=mid-1;
        }
        printf("%d
    ",ans);
    }
    int main(){
        Init(),Work();
        return 0;
    }
    bzoj2732:[HNOI2012]射箭
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define pf(a) ((double)(a)*(a))
    const int N=610;
    int n;
    struct V{
        int to,next;
    }c[N*N*2];
    int first[N],t;
    int di[N],qu[N],front,back;
    int aks[N],wai[N];
    inline void add(int x,int y){
        c[++t].to=y,c[t].next=first[x],first[x]=t;
    }
    struct Line{
        double a,b,c,k;
        int id;
        inline void redef(double x,double y,double z,int name){
            a=x,b=y,c=z,id=name;
            if(x<0)x=-x;
            if(x)a/=x,b/=x,c/=x;
            else{
                if(y<0)y=-y;
                if(y)a/=y,b/=y,c/=y;
            }
            k=std::atan2(-a,b);
        }
    }line[N],queue[N];
    int head,tail;
    inline bool comp(Line a,Line b){
        return a.k!=b.k?a.k<b.k:a.c<b.c;
    }
    inline bool check(Line a,Line b,Line c){
        double x=(a.b*b.c-b.b*a.c)/(b.b*a.a-a.b*b.a);
        double y=(a.a*b.c-b.a*a.c)/(b.a*a.b-a.a*b.b);
        return c.a*x+c.b*y+c.c>0;
    }
    inline void build(int id,int li,int im){
        int i,j=1,m=4;
        line[1].redef(1,0,0,0);
        line[2].redef(-1,0,li,0);
        line[3].redef(0,1,0,0);
        line[4].redef(0,-1,im,0);
        double a,b,c;
        for(i=1;i<=n;++i){
            if(i==id)continue;
            a=2*aks[id]-2*aks[i];
            b=2*wai[id]-2*wai[i];
            c=pf(aks[i])-pf(aks[id])+pf(wai[i])-pf(wai[id]);
            line[++m].redef(a,b,c,i);
        }
        std::sort(line+1,line+(m+1),comp);
        for(i=2;i<=m;++i)
            if(line[i].k!=line[j].k)
                line[++j]=line[i];
        head=tail=0;
        queue[tail++]=line[1];
        queue[tail++]=line[2];
        for(i=3;i<=j;++i){
            while(tail-head>1&&!check(queue[tail-1],queue[tail-2],line[i]))--tail;
            while(tail-head>1&&!check(queue[head],queue[head+1],line[i]))++head;
            queue[tail++]=line[i];
        }
        while(tail-head>1&&!check(queue[tail-1],queue[tail-2],queue[head]))--tail;
        for(i=head;i<tail;++i)
            add(id,queue[i].id);
    }
    inline int bfs(int s){
        memset(di,-1,sizeof(di));
        front=back=0;
        qu[back++]=s;
        di[s]=0;
        int x,i;
        while(front!=back){
            x=qu[front++];
            for(i=first[x];i;i=c[i].next)
                if(di[c[i].to]==-1){
                    if(!c[i].to)return di[x]+1;
                    di[c[i].to]=di[x]+1;
                    qu[back++]=c[i].to;
                }
        }
    }
    inline void Main(){
        memset(first,0,sizeof(first)),t=0;
        scanf("%d",&n);
        int i,w,q,l,m,id;
        double min,dis;
        scanf("%d%d%d%d",&l,&m,&w,&q);
        if(n==0){
            puts("0");
            return;
        }
        for(i=1;i<=n;++i){
            scanf("%d%d",&aks[i],&wai[i]);
            dis=pf(w-aks[i])+pf(q-wai[i]);
            if(i==1||dis<min)
                id=i,min=dis;
        }
        for(i=1;i<=n;++i)
            build(i,l,m);
        printf("%d
    ",bfs(id));
    }
    int main(){
        int T;
        scanf("%d",&T);
        while(T--)
            Main();
        return 0;
    }
    bzoj3199:[Sdoi2013]escape

    一般姿势正确就不会被卡精,但是被卡精卡到怀疑人生也是常有的事儿……做题的时候感觉二分/三分和半平面交有互相替代的关系……

  • 相关阅读:
    使用NPOI导入导出标准Excel
    winform ListView应用之分组、重绘图标、网格线
    在网页中显示CHM
    动态表单(javascript实现)
    批量上传文件时,js验证文件名不能相同
    IE开发人员工具无法使用
    卸载方法 gnu grub version 0.97
    VS.Net 2003/VC6.0常用快捷键集合
    SQL SERVER 与ACCESS、EXCEL的数据转换
    通用获取父节点/子节点/子节点下所有节点ID的存储过程
  • 原文地址:https://www.cnblogs.com/TSHugh/p/8781857.html
Copyright © 2020-2023  润新知