zoukankan      html  css  js  c++  java
  • 几何模版-凸包

    Graham算法

    平均复杂度:N log(N)

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    
    const int Max = 1100;
    #define PI 3.1415926
    struct Point
    {
        int x;
        int y;
    };
    int num;
    Point p[Max];   //原始点
    Point ch[Max];  //凸包点
    //叉乘
    int xmult(const Point& p0, const Point& p1, const Point& p2)
    {
        return (p1.x-p0.x)*(p2.y-p0.y) - (p2.x-p0.x)*(p1.y-p0.y);
    }
    //间距
    double dis(const Point& a, const Point& b)
    {
        return sqrt((double)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
    }
    //极角排序
    bool cmp(const Point& a, const Point& b)
    {
        int ret = xmult(p[0],a,b);
        if(ret>0)
            return true;
        if(ret==0&&dis(p[0],a)<dis(p[0],b))
            return true;
        return false;
    }
    
    
    //Graham(p,n,ch,num);
    //求n个点构成的p点集中的凸包
    //凸包上共num个点按序存于ch数组里。
    void Graham(Point* p, int n, Point* ch, int& top)
    {
        int i,k=0;
        for(i=1; i < n; i++)
        {
            if(p[k].y>p[i].y || ((p[k].y==p[i].y)&&p[k].x>p[i].x))
                k = i;
        }
        swap(p[k],p[0]);//寻找最左下角的点
        sort(p+1,p+n,cmp);
        top = 0;
        ch[top++] = p[0];
        ch[top++] = p[1];
        ch[top++] = p[2];
        for(i = 3; i < n; ch[top++]=p[i++])
            while(top>=2 && xmult(ch[top-2],ch[top-1],p[i])<0)    //左拐判断
                top--;
    }
    
    //test:
    int main()
    {
        int i;
        int n,r,t;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&n,&r);
            {
                for(i = 0; i < n; i++)
                    scanf("%d%d",&p[i].x,&p[i].y);
                Graham(p,n,ch,num);
                double result = PI*r*2;
                for(i = 0; i < num-1; i++)//周长
                    result += dis(ch[i],ch[i+1]);
                result += dis(ch[0],ch[num-1]);
                printf("%.0f
    ",result);
            }
            if(t!=0)
                printf("
    ");
        }
        return 0;
    }

    快速凸包算法

    复杂度:平均Nlog(2N),最优N,最差N^2

    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <math.h>
    #include <algorithm>
    using namespace std;
    struct point
    {
        double x,y;
    };
    struct point p[105],p1[105];
    
    double s[105];
    int d;
    bool cmp(point a,point b)
    {
        if(a.x==b.x)
            return a.y<b.y;
        return a.x<b.x;
    }
    
    double chaji(point a,point b,point c)
    {
        return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
    }
    
    
    //求点集p的凸包,凸包上点的个数为d。按序存入p1数组内
    void hull(int l,int r,point a,point b)
    {         //左边   右边
        int x=l,i=l-1,j=r+1,k;
        point y;
        for(k=l;k<=r;k++)
        if(s[x]<s[k] || s[x]==s[k] && cmp(p[x],p[k])) x=k;
        
        y=p[x];
        for(k=l;k<=r;k++) //左边
        {
            s[++i]=chaji(p[k],a,y);
            if(s[i]>0) swap(p[i],p[k]);
            else i--;
        }
        for(k=r;k>=l;k--)  // 右边
        {
            s[--j]=chaji(p[k],y,b);
            if(s[j]>0) swap(p[j],p[k]);
            else j++;
        }
        if(l<=i) hull(l,i,a,y);
        d++;
        p1[d]=y;
        if(j<=r) hull(j,r,y,b);
    }
    
    double dist(point a,point b)
    {
        return sqrt((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y));
    }
    
    int main()
    {
        int n,i;
        double sum;
        while(~scanf("%d",&n) && n)
        {
            memset(p,0,sizeof(p));
            memset(p1,0,sizeof(p1));
            memset(s,0,sizeof(s));
            sum=0;
            d=1;
    
            for (i=1;i<=n;i++)
                scanf("%lf %lf",&p[i].x,&p[i].y);
            sort(p+1,p+n+1,cmp); //按x从小到大排,x相同:按y从小到大排
            p1[1].x=p[1].x;      //第一个点 一定为凸包点
            p1[1].y=p[1].y;
    
            hull(2,n,p[1],p[1]);
    
            p1[d+1].x=p[1].x;
            p1[d+1].y=p[1].y;
            for(i=1;i<=d;i++) sum+=dist(p1[i],p1[i+1]);
            if(d==2) sum/=2;
            printf("%.2lf
    ",sum);
        }
        return 0;
    }

    步进发

    复杂度:平均 NM(M为凸包上的点的个数)

    适合凸包上的点个数少的时候。即点分布较为随机。

    #include <stdio.h>
    #include <math.h>
    #include <algorithm>
    using namespace std;
    struct point
    {
        double x,y;
    };
    struct point a[1005],b[1005],p[2005],p1[2005];
    //p:遍历全部点 p1:记录凸包的点
    int size;         //凸包点个数
    bool cmp(point a,point b)
    {//按x从小到大排列;x相同的 按y从小到大排列
        if(a.x==b.x) return a.y<b.y;
        return a.x<b.x;
    }
    double chaji(point a,point b,point c)
    {
        return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
    }
    double dist(point a,point b)
    {
        return sqrt((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y));
    }
    
    
    //求点集p的凸包。
    //凸包上点数为size,按序存回p数组;
    void sovle(int n)
    {
        int i;
        double t;
        p1[0]=p[0];     //第一个凸包点是第一个点
        p1[1]=p[1]; //假设..二............二....
        size=1;    //记录当前假设的凸包点
        for(i=2;i<n;i++)//遍历所有点
        {
            t=chaji(p1[size-1],p1[size],p[i]);//算两个凸包点与该点 向量的叉积
            while(t<=0)//叉积<=0  该点不是凸包点
            {
                size--;
                //垂直 或者凸包点全部遍历完
                if(t==0 || size==0) break;
                t=chaji(p1[size-1],p1[size],p[i]);//直到该点遍历完全部凸包点或者 满足>0为凸包点
            }
            p1[++size]=p[i];//记录下一个凸包点
        }
        p1[++size]=p[n-2];
        for(i=n-3;i>=0;i--)//往回找 直到第一个凸包点
        { 
            t=chaji(p1[size-1],p1[size],p[i]);
            while(t<=0)
            {
                size--;
                if(t==0 || size==0) break;
                t=chaji(p1[size-1],p1[size],p[i]);
            }
            p1[++size]=p[i];
        }
    }
    int main()
    {
        int n,i;
        double sum;
        while(~scanf("%d",&n) && n)
        {
            for(i=0;i<n;i++) scanf("%lf%lf",&p[i].x,&p[i].y);
            sort(p,p+n,cmp);
            sovle(n);
            sum=0;
            //计算周长
            for(i=0;i<size;i++) sum=sum+dist(p1[i],p1[i+1]);
            //若只有2个凸包点
            if(size==2) sum=sum/2;
            printf("%.2lf
    ",sum);
        }
        return 0;
    }
  • 相关阅读:
    星空雅梦
    星空雅梦
    星空雅梦
    星空雅梦
    深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)请自取
    Map遍历法则
    c.toArray might (incorrectly) not return Object[]
    JavaGuide
    NIO入门
    Docker应用安装
  • 原文地址:https://www.cnblogs.com/mochenmochen/p/5157131.html
Copyright © 2011-2022 走看看