zoukankan      html  css  js  c++  java
  • 计算几何题目总结

    模板  (只用这一个)   点  线  圆  

    //#include<bits/stdc++.h>
    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <queue>
    #include <map>
    #include <vector>
    #include <set>
    #include <string>
    #include <math.h>
    using namespace std;
    const double eps=1e-8;
    const double pi=acos(-1.0);
    inline double sqr(double x){ return x*x;                                  }
    inline int dcmp(double x)  { if(fabs(x)<eps) return 0;return (x>0? 1: -1);}
    struct Point{
        double x,y;
        Point(){ x=0,y=0; }
        Point(double _x,double _y):x(_x),y(_y){}
        void input(){ scanf("%lf%lf",&x,&y); }
        void output(){ printf("%.2f %.2f
    ",x,y); }
        friend istream &operator >>(istream &os,Point &b){os>>b.x>>b.y;return os;             }
        friend ostream &operator <<(ostream &os,Point &b){os<<b.x<<' '<<b.y;return os;        }
        bool operator ==(const Point &b)const{return  ( dcmp(x-b.x)==0&&dcmp(y-b.y)==0);      }
        bool operator !=(const Point &b)const{return !((dcmp(x-b.x)==0&&dcmp(y-b.y)==0));     }
        bool operator <(const Point &b)const {return (dcmp(x-b.x)==0? dcmp(y-b.y)<0 : x<b.x); }
        double operator ^(const Point &b)const{     return x*b.y-y*b.x;}//叉积
        double operator *(const Point &b)const{     return x*b.x+y*b.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);}
        Point operator *(double a)            {     return Point(x*a,y*a);    }
        Point operator /(double a)            {     return Point(x/a,y/a);    }
        double len2()                         {     return sqr(x)+sqr(y);     }//长度平方
        double len()                          {      return sqrt(len2());     }//长度
        double polar(){  return atan2(y,x);  }//向量的极角   //返回与x轴正向夹角(-pi~pi]
        Point change_len(double r){           //转化为长度为r的向量
            double l=len();
            if(dcmp(l)==0)  return *this;  //零向量
            return Point(x*r/l,y*r/l);
        }
        Point rotate_left() {  return Point(-y,x); }//逆时针旋转90度
        Point rotate_right(){  return Point(y,-x); }//顺时针旋转90度
        Point rotate(Point p,double ang){           //绕点p逆时针旋转ang度
            Point v=(*this)-p;  double c=cos(ang),s=sin(ang);
            return Point(p.x+v.x*c-v.y*s,p.y+v.x*s+v.y*c);
        }
        Point normal(){  return Point(-y/len(),x/len()); }//单位化,逆时针旋转90°
    };
    inline double cross(Point a,Point b)    {   return a.x*b.y-a.y*b.x;                             } //叉积
    inline double dot(Point a,Point b)      {   return a.x*b.x+a.y*b.y;                             } //点积
    double rad(Point a,Point b)             {   return fabs(atan2(fabs(cross(a,b)),dot(a,b)));      }  //两个向量的夹角
    double area2(Point A, Point B, Point C) {   return cross(B-A, C-A);                             }  // 四边形面积
    bool   is_parallel(Point a,Point b)       {   double p=rad(a,b);return dcmp(p)==0||dcmp(p-pi)==0; }//判断向量是否平行
    
    typedef Point Vector;
    double Angle(Vector A, Vector B)        { return acos(dot(A, B)/A.len()/B.len());           }  // 角度
    double dis(Point A,Point B)             { return sqrt( (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));}
    Vector Normal(Vector A)                 { double L =A.len(); return Vector(-A.y/L, A.x/L);   }  //rad为弧度 且为逆时针旋转的角
    bool ToLeftTest(Point a,Point b,Point c){ return cross(b - a, c - b) > 0;                       }  //向量A左转90°的单位法向量
    struct Line{
        Point s,e;
        Line(){}
        Line(Point _s,Point _e):s(_s),e(_e){} //两点确定直线
        Line(Point p,double ang){   //一个点和斜率(弧度制)确定直线
            s=p;
            if(dcmp(ang-pi/2)==0){ e=s+Point(0,1);        }
            else                 { e=s+Point(1,tan(ang)); }
        }
        void input(){ s.input(); e.input(); }
        Point operator &(const Line &b)const{    //求两直线交点
            Point res=s;
            double t=((s-b.s)^(b.s-b.e))/((s-e)^(b.s-b.e));
            res.x+=(e.x-s.x)*t;
            res.y+=(e.y-s.y)*t;
            return res;
        }
    };
    struct Circle{
        Point c;
        double r;
        Circle() {c.x=0; c.y=0; r=0; }
        Circle(Point c,double r):c(c),r(r) {}
        Point point(double a){
            return Point (c.x+cos(a)*r,c.y+sin(a)*r);
        }
    }A,B;
    Point Circle_Cirle(Circle c1, Circle c2){
        double d=dis(c1.c,c2.c);   Point k=c2.c-c1.c;
        double a=k.polar();
        double da=acos( (c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d) );
        Point p1=c1.point(a-da);  //printf("%.10f %.10f
    ",p1.x,p1.y);
        Point p2=c1.point(a+da); // printf("%.10f %.10f
    ",p2.x,p2.y)
        return p1;
    }
    double PolygonArea(vector<Point> p){    //多边形的有向面积,加上绝对值就是面积  正值表示输入点按照逆时针 否则为顺时针
        int n=p.size(); double area=0;
        for(int i=1;i<n-1;i++)  area+=cross(p[i]-p[0],p[i+1]-p[0]);
        return fabs(area/2); // 可改
    }
    double PolygonLength(vector<Point> vp){  //多边形周长
        int m=vp.size(); double area=0;
        for(int i=0;i<m;i++) area+=dis(vp[i],vp[(i+1)%m]);
        return fabs(area/2);
    }
    bool up(Point a,Point b)  { if(a.x!=b.x) return a.x<b.x;  return a.y<b.y; }
    bool cmp2(Point a,Point b){ Point c; return cross(a-c,b-c)>0;     }
    bool cmp1(Point a,Point b) // (-pi,pi]
    {
        if( abs(atan2(a.y,a.x)-atan2(b.y,b.x))>eps )
            return atan2(a.y,a.x)<atan2(b.y,b.x);
        else return a.x<b.x;
    }
    int Quadrant(Point a)//象限排序,注意包含四个坐标轴
    {
        if(a.x>0&&a.y>=0)  return 1;
        if(a.x<=0&&a.y>0)  return 2;
        if(a.x<0&&a.y<=0)  return 3;
        if(a.x>=0&&a.y<0)  return 4;
    }
    bool cmp3(Point a,Point b)  //先按象限从小到大排序 再按极角从小到大排序
    {
        if(Quadrant(a)==Quadrant(b))//返回值就是象限
            return cmp1(a,b);
        else Quadrant(a)<Quadrant(b);
    }
    bool cmp(Point a, Point b)//先按象限排序,再按极角排序,再按远近排序
    {
        if (a.y == 0 && b.y == 0 && a.x*b.x <= 0)return a.x>b.x;
        if (a.y == 0 && a.x >= 0 && b.y != 0)return true;
        if (b.y == 0 && b.x >= 0 && a.y != 0)return false;
        if (b.y*a.y <= 0)return a.y>b.y;
        Point one;
        one.y = one.x = 0;
        return cross(one-a,one-b) > 0 || (cross(one-a,one-b) == 0 && a.x < b.x);
    }
    void tubao(vector<Point> vs){
        Point pa[60];    Point pt[60];
        int n=vs.size();
        for(int i=0;i<n;i++) pa[i]=vs[i];
        sort(pa,pa+n,up);
        int m=0;
        for(int i=0;i<n;i++)
        {
            while(m>1 && cross(pt[m-1]-pt[m-2],pa[i]-pt[m-2])<=0) m--;
            pt[m++]=pa[i];
        }
        int k=m;
        for(int i=n-2;i>=0;i--)
        {
            while(m>k && cross(pt[m-1]-pt[m-2],pa[i]-pt[m-2])<=0) m--;
            pt[m++]=pa[i];
        }
        if(n>1) m--;  //  1-m
    }
    const int maxn=60;
    Point pa[maxn];
    int main(){
        Point s; scanf("%lf %lf",&s.x,&s.y);
        int tot=1;
        while(~scanf("%lf %lf",&pa[tot].x,&pa[tot].y) && pa[tot].x!=1100) {++tot; }
        //cout<<tot<<endl;
        sort(pa+1,pa+tot,cmp2);
        printf("(%.0f,%.0f)
    ",s.x,s.y);
        for(int i=1;i<tot;i++){
            printf("(%.0f,%.0f)
    ",pa[i].x,pa[i].y);
        }
    }
    View Code

    平面直线图   ( 求直线交的多边形第K大模板  )

    struct PSLG{    //平面直线图 处理平面内所有直线围成的所有多边形 传入直线交点之间的每条线段
        struct Edge{
            int from,to;
            double ang;
            Edge(){ ang=from=to=0; }
            Edge(int s,int t,double a){ from=s,to=t,ang=a; }
        };
        int n,m,face_cnt;   //平面个数 包括外面最大的多边形
        double area[MAXN];  //每个多边形面积
        Point point[MAXN];  //平面内所有的点
        vector<Edge>edge;
        vector<int>G[MAXN];
        vector<vector<Point> >face;
        int vis[2*MAXN],left[2*MAXN],pre[2*MAXN];   //left表示这条边的左侧属于哪个面
        void Init(){
            face.clear();
            edge.clear();
            for(int i=0;i<n;i++)    G[i].clear();
            n=m=0;
        }
        PSLG(){ Init(); }
        void AddEdge(int from, int to){             //需要建立反向边帮助寻找下一条边
           edge.pb(Edge(from,to,(point[to]-point[from]).polar()));
           edge.pb(Edge(to,from,(point[from]-point[to]).polar()));
           m=edge.size();
           G[from].pb(m-2);
           G[to].pb(m-1);
        }
        void Build(){
            for(int u=0;u<n;u++){
                int d=G[u].size();
                for(int i=0;i<d;i++)
                    for(int j=i+1;j<d;j++)
                        if(edge[G[u][i]].ang>edge[G[u][j]].ang)
                            swap(G[u][i],G[u][j]);
                for(int i=0;i<d;i++)    pre[G[u][(i+1)%d]]=G[u][i]; //从u出发的i条边顺时针旋转的第一条边是pre[i]
            }
            face_cnt=0; memset(vis,0,sizeof(vis));
            for(int u=0;u<n;u++){
                for(int i=0;i<G[u].size();i++){
                    int e=G[u][i];
                    if(!vis[e]){
                        face_cnt++;
                        vector<Point> polygon;
                        while(1){
                            vis[e]=1;
                            left[e]=face_cnt;
                            int from=edge[e].from;
                            polygon.pb(point[from]);
                            e=pre[e^1];         //逆时针旋转最多的一条边即为顺时针转动的第一条边
                            if(e==G[u][i])  break;
                        }
                        face.pb(polygon);
                   }
                }
            }
            for(int i=0;i<face_cnt;i++)  area[i]=polygon_area(face[i]);
            
            
            /*   包括外面最大的
            int n;  scanf("%d",&n);
            for(int i=0;i<n;i++)    line[i].input();
            for(int i=0;i<n;i++){
                for(int j=i+1;j<n;j++)
                    if(!is_parallel(line[i].e-line[i].s,line[j].e-line[j].s)){
                        Point inter=line[i]&line[j];
                        pslg.point[pslg.n++]=inter;
                        point[i].pb({dot(inter-line[i].s,line[i].e-line[i].s),pslg.n-1});
                        point[j].pb({dot(inter-line[j].s,line[j].e-line[j].s),pslg.n-1});
                    }
                sort(point[i].begin(),point[i].end());
                for(int j=1;j<point[i].size();j++)  pslg.AddEdge(point[i][j-1].se,point[i][j].se);
            }
        */
        }
    };
    View Code

    直线相交检测     2-重合 1-相交 0-不相交  两点式  double 类型    

    int check_line_line(Line A,Line B)
    {
        Point a=A.a; Point b=A.b;
        Point c=B.a; Point d=B.b;
        double A1=b.y-a.y,B1=-(b.x-a.x),C1=b.y*a.x-b.x*a.y;
        double A2=d.y-c.y,B2=-(d.x-c.x),C2=d.y*c.x-d.x*c.y;
        double k=A1*B2-A2*B1;
        if(fabs(k)<eps)
        {
            if(fabs( C2*A1-C1*A2)<eps && fabs(B1*C2-C1*B2)<eps ) return 2
            else                   return 0;
        }
        return 1;
    }
    直线相交检测

    直线相交求交点  1-相交情况求交点  两点式  double 类型  

    Point line_line(Line A,Line B)
    {
        Point a=A.a; Point b=A.b;
        Point c=B.a; Point d=B.b;
        double A1=b.y-a.y,B1=-(b.x-a.x),C1=b.y*a.x-b.x*a.y;
        double A2=d.y-c.y,B2=-(d.x-c.x),C2=d.y*c.x-d.x*c.y;
        double k=A1*B2-A2*B1;
        double x=-(B1*C2-C1*B2)*1.000000000/k;
        double y= (A1*C2-C1*A2)*1.00000000/k;
        Point ans;
        ans.x=y;
        ans.y=y;
        return ans;
    }
    直线相交求交点

     poj 1269  两条直线相交 判断  ( 重合  相交  不相交 )

    void XX(Line A,Line B)
    {
        Point a=A.a; Point b=A.b;
        Point c=B.a; Point d=B.b;
        double A1=b.y-a.y,B1=-(b.x-a.x),C1=b.y*a.x-b.x*a.y;
        double A2=d.y-c.y,B2=-(d.x-c.x),C2=d.y*c.x-d.x*c.y;
        double k=A1*B2-A2*B1;
        if(fabs(k)<eps)
        {
            if( fabs( C2*A1-C1*A2)<eps && fabs(B1*C2-C1*B2)<eps ) printf("LINE
    ");
            else                   printf("NONE
    ");
        }
        else
        {
                double x=-(B1*C2-C1*B2)*1.000000000/k;
                double y=(A1*C2-C1*A2)*1.00000000/k;
                printf("POINT %.2f %.2f
    ",x,y);
        }
    }
    直线相交

     线段相交    1-相交 0-不相交   (非严格相交 严格相交)

    bool check_se_se_uff(Segment A,Segment B)
    {
        Point a=A.a; Point b=A.b;Point c=B.a; Point d=B.b;
        return Cross(a-c,a-d)*Cross(b-c,b-d)<=0 && Cross(c-a,c-b)*Cross(d-a,d-b)<=0 ;
    
    }
    bool check_se_se_ff(Segment A,Segment B){
        Point a=A.a; Point b=A.b;Point c=B.a; Point d=B.b;
        return
        max(A.a.x,A.b.x) >= min(B.a.x,B.b.x) &&
        max(B.a.x,B.b.x) >= min(A.a.x,A.b.x) &&
        max(A.a.y,A.b.y) >= min(B.a.y,B.b.y) &&
        max(B.a.y,B.b.y) >= min(A.a.y,A.b.y) &&
        Cross(a-c,a-d)*Cross(b-c,b-d)<=0 &&
        Cross(c-a,c-b)*Cross(d-a,d-b)<=0 ;
    }
    线段相交检测

    线段交点求法同直线一样 

    hdu  3272  枚举中间ABCD   P(ABCD)P

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+10;
    const double pi=acos(-1.0);
    const double D_MAX=1e100;
    const double D_MIN=-1e100;
    const double eps=1e-9;
    int sgn(double x){ if(fabs(x) < eps)return 0;  if(x >0) return 1; return -1; }
    int dcmp(double x, double y){ if(fabs(x - y) < eps) return 0; if(x > y) return 1;return -1;}
    void usehanshu(){double x;}//floor(x)向下取整函数ceil(x)向上取整函数round(x)四舍五入函数
    struct Point  { int  x,y;   Point(int a=0,int b=0)                     { x=a;y=b; };   };
    struct Segment{ Point a,b;  Segment(Point x=Point(0,0),Point y=Point(0,0) )  { a=x;b=y; };   };
    struct Line   { Point a,b;  Line(Point x=Point(0,0),Point y=Point(0,0) )     { a=x;b=y; };   };
    double dis(Point A,Point B) { return sqrt( 1.0*(A.x-B.x)*(A.x-B.x)+1.0*(A.y-B.y)*(A.y-B.y) );  }
    
    /*-----------show time ---------------------*/
    int a[5];
    double make_x(Point p,Point c){
        if(p.y*c.y>0) p.y=-p.y;
        return dis(p,c);
    }
    double make_y(Point p,Point c){
        if(p.x*c.x>0) p.x=-p.x;
        return dis(p,c);
    }
    double make_xy(Point p,Point c){
        if(p.x*c.x>0) p.x=-p.x;
        if(p.y*c.y>0) p.y=-p.y;
        return dis(p,c);
    }
    int main(){
        int T; scanf("%d",&T);
        while(T--){
            double num=1e9+10;
            Point c; Point d; Point p; scanf("%d %d %d %d %d %d",&c.x,&c.y,&d.x,&d.y,&p.x,&p.y);
            for(int i=1;i<=4;i++) a[i]=i;
            do{
                int t=0; Point w=p;  double ans=0;
                for(int i=1;i<=4;i++){
                    if(a[i]==1 || a[i]==2 ) t+=a[i];
                    else if(a[i]==3){
                        if(t==0)      ans+=dis(w,c);
                        else if(t==1) ans+=make_x(w,c);
                        else if(t==2) ans+=make_y(w,c);
                        else          ans+=make_xy(w,c);
                        w=c; t=0;
                    }
                    else if(a[i]==4){
                        if(t==0)      ans+=dis(w,d);
                        else if(t==1) ans+=make_x(w,d);
                        else if(t==2) ans+=make_y(w,d);
                        else          ans+=make_xy(w,d);
                        w=d; t=0;
                    }
                }
                if(t==0)      ans+=dis(w,p);
                else if(t==1) ans+=make_x(w,p);
                else if(t==2) ans+=make_y(w,p);
                else          ans+=make_xy(w,p);
                num=min(ans,num);
            }
            while(next_permutation(a+1,a+1+4));
            printf("%.2f
    ",num);
        }
    }
    HDU 3272

    poj 1873 凸包

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <queue>
    #include <map>
    #include <vector>
    #include <set>
    #include <string>
    #include <math.h>
    #define ll long long
    using namespace std;
    const int maxn=1e5+10;
    struct Point  { double x,y;   Point(double a=0,double b=0) { x=a;y=b; };   };
    typedef Point Vector;
    Vector operator - (Point  A, Point  B){ return Vector(A.x-B.x, A.y-B.y); } // 向量生成
    double Cross(Vector A, Vector B) { return A.x*B.y-A.y*B.x;   }  // 叉积
    double dis(Point A,Point B) { return sqrt( (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y) );  }
    Point pa[maxn];
    int a[maxn];
    int b[maxn];
    bool up(Point a,Point b)
    {
        if(a.x!=b.x) return a.x<b.x;
        return a.y<b.y;
    }
    vector<Point> vs;
    vector<int> vp;
    vector<int> vc;
    double work(){
        Point pa[60];
        Point pt[60];
        int n=vs.size();
        for(int i=0;i<n;i++) pa[i]=vs[i];
        sort(pa,pa+n,up);
        int m=0;
        for(int i=0;i<n;i++)
        {
            while(m>1 && Cross(pt[m-1]-pt[m-2],pa[i]-pt[m-2])<=0) m--;
            pt[m++]=pa[i];
        }
        int k=m;
        for(int i=n-2;i>=0;i--)
        {
            while(m>k && Cross(pt[m-1]-pt[m-2],pa[i]-pt[m-2])<=0) m--;
            pt[m++]=pa[i];
        }
        if(n>1) m--;
        double ans=0;
        for(int i=1;i<m;i++) ans+=dis(pt[i],pt[i+1]); ans+=dis(pt[m],pt[1]);
        return ans;
    }
    int main(){
       int n; int tot=0;
       while(scanf("%d",&n) && n!=0){
         for(int i=1;i<=n;i++){
            scanf("%lf %lf",&pa[i].x,&pa[i].y);
              scanf("%d %d",&a[i],&b[i]);
         }
         vp.clear();
         int ans1=0;
         int ans2=0;
         double ans3=0;
         for(int i=0;i<(1<<n);i++){
            vs.clear();
            vc.clear();
            int value=0;
            int tree=0;
            int num=0;
            for(int j=1;j<=n;j++){
                if(i&(1<<(j-1))){  // 砍掉
                    tree+=b[j];   vc.push_back(j);
                }else {   // 剩余
                    value+=a[j]; vs.push_back(pa[j]); num++;
                }
            }
            double k=work();  ;
            if(tree>=k){
                if(value>ans1){
                    ans1=value; ans2=num;  ans3=tree-k; vp.clear();
                    for(int w=0;w<vc.size();w++) vp.push_back(vc[w]);
                }
                else if(value==ans1){
                   if(num>=ans2){
                     ans1=value; ans2=num;  ans3=tree-k; vp.clear();
                    for(int w=0;w<vc.size();w++) vp.push_back(vc[w]);
                   }
                }
            }
         }
         if(tot!=0) printf("
    ");
         printf("Forest %d
    ",++tot);
         printf("Cut these trees:"); for(int i=0;i<vp.size();i++){ printf(" %d",vp[i]); } printf("
    ");
         printf("Extra wood: %.2f
    ",ans3);
    
       }
    }
    View Code

    poj 2007 凸包

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <queue>
    #include <map>
    #include <vector>
    #include <set>
    #include <string>
    #include <math.h>
    #define ll long long
    using namespace std;
    const int maxn=1e5+10;
    struct Point  { double x,y;   Point(double a=0,double b=0) { x=a;y=b; };   };
    typedef Point Vector;
    Vector operator - (Point  A, Point  B){ return Vector(B.x-A.x, B.y-A.y); } // 向量生成
    double Cross(Vector A, Vector B) { return A.x*B.y-A.y*B.x;   }  // 叉积
    Point pa[maxn];
    bool cmp1(Point a,Point b){ return atan2(a.y,a.x)<atan2(b.y,b.x); }
    bool cmp2(Point a,Point b){ Point c; return Cross(c-a,c-b)>0;     }
    int main(){
        Point s; scanf("%lf %lf",&s.x,&s.y);
        int tot=1;
        while(~scanf("%lf %lf",&pa[tot].x,&pa[tot].y) && pa[tot].x!=1100) {++tot; }
        //cout<<tot<<endl;
        sort(pa+1,pa+tot,cmp2);
        printf("(%.0f,%.0f)
    ",s.x,s.y);
        for(int i=1;i<tot;i++){
            printf("(%.0f,%.0f)
    ",pa[i].x,pa[i].y);
        }
    }
    排序
  • 相关阅读:
    PMO的重要性
    idea CPU过高问题
    近期面试心得
    Spring-Eureka
    BIO/NIO
    redis redlock
    nmon 安装及使用 【linux环境】
    一致性hash 算法
    gossip协议了解
    00008
  • 原文地址:https://www.cnblogs.com/Andromeda-Galaxy/p/11152067.html
Copyright © 2011-2022 走看看