zoukankan      html  css  js  c++  java
  • 半平面交学习笔记

    半平面交的具体过程原理再次不再过多赘述,只是整理一些细节。

    1、设置边界,为了防止边界出锅,我们需要框一个大框,具体长这样。

        b[++tot]=node(-inf,inf,-inf,-inf);b[++tot]=node(-inf,-inf,inf,-inf);
        b[++tot]=node(inf,-inf,inf,inf);b[++tot]=node(inf,inf,-inf,inf);

    2、把每条线段构造出来,然后用atan2算出线段与x轴的夹角。

        for(int i=1;i<=tot;++i)b[i].ang=atan2(b[i].y.y-b[i].x.y,b[i].y.x-b[i].x.x);

    3、将所有线段按照夹角排序,如果夹角相等就看哪条线段更靠里,这个可以用叉积算。

    bool operator <(const node &b)const{
            if(fabs(ang-b.ang)<eps)return (y-x)*(b.x-x)<eps; 
            else return ang<b.ang;
        }

    4、这个非常关键,如果有平行的线段在后面算的时候会出锅,所以我们要去重,因为我们排过序了,所以我们直接保留相同夹角的第一条线段就好了。

        for(int i=1;i<=tot;++i)if(fabs(b[i].ang-b[i-1].ang)>eps)c[++top]=b[i];
        for(int i=1;i<=top;++i)b[i]=c[i];tot=top;

    5、加入每条线段,维护单调队列。

        h=1;t=2;q[h]=b[1];q[t]=b[2];p[h]=jiao(b[1],b[2]);
        for(int i=3;i<=tot;++i){
            while(h<t&&left(b[i],p[t-1]))t--;
            while(h<t&&left(b[i],p[h]))h++;
            q[++t]=b[i];p[t-1]=jiao(q[t],q[t-1]);
        }
        while(h<t&&left(q[t],p[h]))h++;
        while(h<t&&left(q[h],p[t-1]))t--;

    6、维护时我们要判断一条线段是否在点的左边,这个可以用叉积算。

    inline bool left(node b,P a){return (a-b.x)*(b.y-b.x)>eps;}

    7、我们开需要求出两条线段的交点,这个用面积(还是叉积)算。

    inline point jiao(line a,line b){return b.a+(b.b-b.a)*(((b.a-a.a)*(a.b-a.a))/((a.b-a.a)*(b.b-b.a)));}

    8、最后我们用叉积算出多边形的面积

        for(int i=h+2;i<=t;++i)ans+=(p[i]-p[h])*(p[i-1]-p[h])/2;

    HNOI2003多边形

    一开始以为要先极角排序一下,然后WA到死。

    发现点是按顺序给的。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm> 
    #define double double
    #define N 2002
    #define inf 2e9
    using namespace std;
    int n,top,tot,h,t;
    double ans;
    const double eps=1e-9;
    struct point{
        double x,y;
        point operator +(const point &b)const{return point{x+b.x,y+b.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;}
        point operator *(const double &b)const{return point{x*b,y*b};}
    }d[N],p[N];
    inline double dis(point a,point b){return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);}
    struct line{
       point a,b;double ang;
       line(){}
       line(double aa,double bb,double cc,double dd){a.x=aa;a.y=bb;b.x=cc;b.y=dd;}
       bool operator <(const line &x)const{
          if(fabs(ang-x.ang)<eps)return (b-a)*(x.a-a)<eps;
          else return ang<x.ang;
       }
    }l[N],c[N],q[N];
    inline bool cmp(point a,point b){
        double cj=(a-d[1])*(b-d[1]);
        return (cj>0)||(fabs(cj)<eps&&dis(a,d[1])<dis(b,d[1])); 
    }
    inline bool left(line a,point b){return (b-a.a)*(a.b-a.a)>eps;}
    inline point jiao(line a,line b){return b.a+(b.b-b.a)*(((b.a-a.a)*(a.b-a.a))/((a.b-a.a)*(b.b-b.a)));}
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;++i)scanf("%lf%lf",&d[i].x,&d[i].y);
    /*    int ji=1;
        for(int i=2;i<=n;++i)if(d[i].x<d[ji].x||(d[i].x==d[ji].x&&d[i].y<d[ji].y))ji=i;
        swap(d[ji],d[1]);
        sort(d+2,d+n+1,cmp);*/
        reverse(d+1,d+n+1);
        for(int i=2;i<=n;++i)l[i-1]=line(d[i-1].x,d[i-1].y,d[i].x,d[i].y);
        l[n]=line(d[n].x,d[n].y,d[1].x,d[1].y);tot=n;
        l[++tot]=line(-inf,inf,-inf,-inf);l[++tot]=line(-inf,-inf,inf,-inf);
        l[++tot]=line(inf,-inf,inf,inf);l[++tot]=line(inf,inf,-inf,inf);
        for(int i=1;i<=tot;++i)l[i].ang=atan2(l[i].b.y-l[i].a.y,l[i].b.x-l[i].a.x);
        sort(l+1,l+tot+1);
        for(int i=1;i<=tot;++i)if(fabs(l[i].ang-l[i-1].ang)>eps)c[++top]=l[i];
        for(int i=1;i<=top;++i)l[i]=c[i];tot=top;
        h=1;t=2;q[h]=l[1];q[t]=l[2];p[1]=jiao(q[1],q[2]);
        for(int i=3;i<=tot;++i){
            while(h<t&&left(l[i],p[t-1]))t--;
            while(h<t&&left(l[i],p[h]))h++;
            q[++t]=l[i];p[t-1]=jiao(q[t],q[t-1]); 
        }
        while(h<t&&left(q[t],p[h]))h++;
        while(h<t&&left(q[h],p[t-1]))t--;//
        p[t]=jiao(q[h],q[t]);
        for(int i=h+2;i<=t;++i)ans+=(p[i]-p[h])*(p[i-1]-p[h])/2;
        ans=fabs(ans);
        printf("%.2lf",ans);
        return 0;
    }
    View Code

    CQOI2006凸多边形

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #define N 10002
    #define inf 2e9
    #define double long double
    using namespace std;
    const double eps=1e-9;
    int n,tot,h,t,m,top;
    double x[N],y[N],ans;
    inline int rd(){
        int x=0;char c=getchar();bool f=0;
        while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        return f?-x:x;
    }
    struct P{
        double x,y;
        P operator +(const P &b)const{return P{x+b.x,y+b.y};}
        P operator -(const P &b)const{return P{x-b.x,y-b.y};}
        double operator *(const P &b)const{return x*b.y-y*b.x;}
        P operator *(const double &b)const{return P{x*b,y*b};}
        double operator ^(const P &b)const{return x*b.x+y*b.y;}
        inline void print(){
            cout<<x<<" "<<y<<endl;
        }
    }p[N];
    struct node{
        P x,y;double ang;
        node(){}
        node(int a,int b,int c,int d){x.x=a;x.y=b;y.x=c;y.y=d;ang=0;}
        bool operator <(const node &b)const{
            if(fabs(ang-b.ang)<eps)return (y-x)*(b.x-x)<eps; 
            else return ang<b.ang;
        }
        inline void print(){
            cout<<x.x<<" "<<x.y<<" "<<y.x<<" "<<y.y<<endl;
        }
    }b[N],q[N],c[N];
    inline P jiao(node a,node b){
        double k=((b.x-a.x)*(a.y-a.x))/((a.y-a.x)*(b.y-b.x));
        return b.x+(b.y-b.x)*k;
    } 
    inline bool left(node b,P a){return (a-b.x)*(b.y-b.x)>eps;}
    int main(){
        n=rd();
        b[++tot]=node(-inf,inf,-inf,-inf);b[++tot]=node(-inf,-inf,inf,-inf);
        b[++tot]=node(inf,-inf,inf,inf);b[++tot]=node(inf,inf,-inf,inf);
        for(int i=1;i<=n;++i){
            m=rd();
            x[1]=rd();y[1]=rd();
            for(int j=2;j<=m;++j){
                x[j]=rd();y[j]=rd();
                b[++tot]=node(x[j-1],y[j-1],x[j],y[j]);
            }
            b[++tot]=node(x[m],y[m],x[1],y[1]);
        }
        for(int i=1;i<=tot;++i)b[i].ang=atan2(b[i].y.y-b[i].x.y,b[i].y.x-b[i].x.x);
        sort(b+1,b+tot+1);
        for(int i=1;i<=tot;++i)if(fabs(b[i].ang-b[i-1].ang)>eps)c[++top]=b[i];
        for(int i=1;i<=top;++i)b[i]=c[i];tot=top;
        h=1;t=2;q[h]=b[1];q[t]=b[2];p[h]=jiao(b[1],b[2]);
        for(int i=1;i<=tot;++i){
            while(h<t&&left(b[i],p[t-1]))t--;
            while(h<t&&left(b[i],p[h]))h++;
            q[++t]=b[i];p[t-1]=jiao(q[t],q[t-1]);
        }
        while(h<t&&left(q[t],p[h]))h++;
        while(h<t&&left(q[h],p[t-1]))t--;
        if(t-h+1<=2){printf("0.000
    ");return 0;}
        p[t]=jiao(q[h],q[t]);
        for(int i=h+2;i<=t;++i)ans+=(p[i]-p[h])*(p[i-1]-p[h])/2;
        ans=fabs(ans);
        printf("%.3LF",ans);
        return 0;
    } 
    View Code

    HNOI2012射箭

    瞎**化简一下二次函数,发现这就是半平面交,外面套个二分答案就可以了。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #define inf 1e14 
    #define N 220002
    #define double long double
    using namespace std;
    typedef long long ll;
    int tot,n;
    const double eps=1e-14;
    inline ll rd(){
        ll x=0;char c=getchar();bool f=0;
        while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        return f?-x:x; 
    }
    struct node{double x,y1,y2;};
    struct point{
        double x,y;
        point operator +(const point &b)const{return point{x+b.x,y+b.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;}
        point operator *(const double &b)const{return point{x*b,y*b};}
    }p[N];
    struct line{
        point a,b;double ang;int id;
        line(){id=0;} 
        line(double x1,double x2,double x3,double x4){a.x=x1;a.y=x2;b.x=x3;b.y=x4;id=ang=0;} 
        bool operator <(const line &x)const{
            if(ang==x.ang)return (b-a)*(x.a-a)>eps;
            return ang<x.ang;
        }
    }l[N],a[N],q[N];
    inline point jiao(line a,line b){//?????
        double k=((a.b-a.a)*(b.a-a.a))/((b.b-b.a)*(a.b-a.a));
        return b.a+(b.b-b.a)*k;
    }
    bool left(point x,line b){return (x-b.a)*(b.b-b.a)>eps;}
    inline bool check(int mid){
        int top=0;
        for(int i=1;i<=tot;++i)if(l[i].id<=mid)if(!top||fabs(l[i].ang-a[top].ang)>eps)a[++top]=l[i];
        int h=1,t=2;q[1]=a[1];q[2]=a[2];p[1]=jiao(a[1],a[2]);
        for(int i=3;i<=top;++i){
            while(h<t&&left(p[t-1],a[i]))t--;
            while(h<t&&left(p[h],a[i]))h++;
            q[++t]=a[i];p[t-1]=jiao(q[t-1],q[t]);
        } 
        while(h<t&&left(p[t-1],q[h]))t--;
        while(h<t&&left(p[h],q[t]))h++;
        //cout<<mid<<" "<<h<<" "<<t<<endl;
        return t-h>=2;
    }
    int main(){
        n=rd();double x,y1,y2;
        l[++tot]=line(-inf,inf,-inf,-inf);l[++tot]=line(-inf,-inf,inf,-inf);
        l[++tot]=line(inf,-inf,inf,inf);l[++tot]=line(inf,inf,-inf,inf);
        for(int i=1;i<=n;++i){
            x=rd();y1=rd();y2=rd();
            l[++tot].a.x=-1;l[tot].a.y=y1/x+x;
            l[tot].b.x=1;l[tot].b.y=y1/x-x;l[tot].id=i;
            l[++tot].a.x=1;l[tot].a.y=y2/x-x;
            l[tot].b.x=-1;l[tot].b.y=y2/x+x;l[tot].id=i;
        }
        for(int i=1;i<=tot;++i)l[i].ang=atan2(l[i].b.y-l[i].a.y,l[i].b.x-l[i].a.x);
        sort(l+1,l+tot+1);
        int l=0,r=n,ans=0;
        while(l<=r){
            int mid=(l+r)>>1;
            if(check(mid)){ans=mid;l=mid+1;} 
            else r=mid-1;
        }
        printf("%d",ans);
        return 0;
    } 
    View Code
  • 相关阅读:
    C++运算符优先级
    UNREFERENCED_PARAMETER
    Eclipse无法查看源码 提示source not found
    JAVAWEB dbutils执行sql命令并遍历结果集时不能查到内容的原因
    JAVAWEB和数据库 Mysql连接不上的原因及解决方案
    电子设备 Kindle如何删除书籍或漫画
    JAVA StringUtils需要导入的包
    JAVAWEB servlet和jsp的权限访问控制
    JAVAWEB servlet验证登录时进行完全的非空判断防止空值登录
    JAVAWEB 遍历mysql结果集时 字段为0、false、null的问题
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10170902.html
Copyright © 2011-2022 走看看