• 凸包几种构造方法+旋转卡壳


    一、分治法

    找到横坐标最小和最大的两个点p0p1,它们一定在凸包上(横坐标最小、最大的若多个点,随意取一个即可),然后在直线p0p1的其中一边找离直线最远的一个点,它也一定在凸包上,以后每次向外部(内部的点一定不是凸包上的点)找离现有直线最远的一个点;再在直线p0p1的另一边进行同样的操作

    实现细节:一开始将点用xy坐标进行双关键字排序,事实上每次找到一个点之后,相当于把原(矩形)空间分成了两个子(矩形)空间,距离直接用三角形有向面积判断即可,有向面积判断还能顺便判断是在内部还是外部

    时间复杂度事实上和快排一样取决于数据分布,一般认为是O(nlogn)

    二、Jarvis步进法

    找到纵坐标最小的点作为起点,每次找极角最小(相等则取最远)的点作为凸包下一个点

    时间复杂度O(hn)h为凸包上点数

    三、Graham扫描法

    找到纵坐标最小的点作为起点,以该点为极点进行极角排序,用一个栈维护前进方向

    时间复杂度O(nlogn)

    四、Andrew算法(推荐使用)

    xy进行双关键字排序,找到横坐标最小的点,然后用一个栈维护前进方向,求一个下凸包再求一个上凸包

    时间复杂度O(nlogn)

     hdu1392 一道裸凸包题,但数据有点奇怪,n=2时要特判

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    #define rep(i,a,b) for(int i=a;i<=b;++i)
    #define arcrep(i,a,b) for(int i=a;i>=b;--i)
    
    const int MAXN=200000+10;
    
    struct point{
        long long x,y;
        point(){}
        point (long long a,long long b): x(a),y(b) {}
    
        friend point operator + (const point &a,const point &b){
            return point(a.x+b.x,a.y+b.y);
        }
    
        friend point operator - (const point &a,const point &b){
            return point(a.x-b.x,a.y-b.y);
        }
    
        friend point operator * (const long long &r,const point &a){
            return point(r*a.x,r*a.y);
        }
    
        friend bool operator == (const point &a,const point &b){
            return a.x==b.x && a.y==b.y;
        }
    
        double norm(){
            return sqrt(x*x+y*y);
        }
    };
    
    inline long long det(point a,point b) {return a.x*b.y-a.y*b.x;}
    inline long long dot(point a,point b) {return a.x*b.x+a.y*b.y;}
    inline double dist(point a,point b) {return (a-b).norm();}
    
    
    point ori[MAXN+10],con[MAXN+10];
    
    bool cmp(const point &a,const point &b)
    {
        return (a.x<b.x || (a.x==b.x && a.y<b.y));
    }
    
    //Graham算法 input:ori数组 output:con数组
    int Graham(int n)
    {
        sort(ori+1,ori+n+1,cmp);        //排序后第1和第n个点必定属于凸包
        int temp=0;
        rep(i,1,n)
        {
            while (temp>=2 && det(con[temp]-con[temp-1],ori[i]-con[temp])<=0) --temp;
            con[++temp]=ori[i];
        }
        int ans=temp;
        arcrep(i,n-1,1)
        {
            while (ans>temp && det(con[ans]-con[ans-1],ori[i]-con[ans])<=0) --ans;
            con[++ans]=ori[i];
        }
        if (n>1) --ans;
        return ans;
    }
    
    int n,num;
    double ans;
    int main() { while (~scanf("%d",&n)) { if (n==0) break; rep(i,1,n) scanf("%lld%lld",&ori[i].x,&ori[i].y); if (n==2) {printf("%.2f ",dist(ori[1],ori[2]));continue;} num=Graham(n); ans=0; rep(i,1,num-1) ans+=dist(con[i],con[i+1]); ans+=dist(con[num],con[1]); printf("%.2f ",ans); } return 0; }

    旋转卡壳的核心思路是寻找对踵点

    旋转卡壳裸题poj2187(可直接用int或者long long)

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    #define rep(i,a,b) for(int i=a;i<=b;++i)
    #define arcrep(i,a,b) for(int i=a;i>=b;--i)
    
    const int MAXN=200000+10;
    struct point{
        int x,y;
        point(){}
        point (int a,int b): x(a),y(b) {}
    
        friend point operator + (const point &a,const point &b){
            return point(a.x+b.x,a.y+b.y);
        }
    
        friend point operator - (const point &a,const point &b){
            return point(a.x-b.x,a.y-b.y);
        }
    
        friend point operator * (const int &r,const point &a){
            return point(r*a.x,r*a.y);
        }
    
        friend bool operator == (const point &a,const point &b){
            return a.x==b.x && a.y==b.y;
        }
    
        int sqrnorm(){
            return x*x+y*y;
        }
    };
    
    inline int det(point a,point b) {return a.x*b.y-a.y*b.x;}
    inline int dot(point a,point b) {return a.x*b.x+a.y*b.y;}
    inline int sqrdist(point a,point b) {return (a-b).sqrnorm();}
    
    point ori[MAXN+10],con[MAXN+10];
    
    bool cmp(const point &a,const point &b)
    {
        return (a.x<b.x || (a.x==b.x && a.y<b.y));
    }
    
    //Graham算法 input:ori数组 output:con数组
    int Graham(int n)
    {
        sort(ori+1,ori+n+1,cmp);        //排序后第1和第n个点必定属于凸包
        int temp=0;
        rep(i,1,n)
        {
            while (temp>=2 && det(con[temp]-con[temp-1],ori[i]-con[temp])<=0) --temp;
            con[++temp]=ori[i];
        }
        int ans=temp;
        arcrep(i,n-1,1)
        {
            while (ans>temp && det(con[ans]-con[ans-1],ori[i]-con[ans])<=0) --ans;
            con[++ans]=ori[i];
        }
        if (n>1) --ans;
        return ans;
    }
    
    int mindist(int m)
    {
        int ans=0;
        int temp;
        con[m+1]=con[1];
        int j=2;
        for (int i=1;i<=m;++i)
        {
    
            while (abs(det(con[j]-con[i],con[i+1]-con[i]))<abs(det(con[j+1]-con[i],con[i+1]-con[i])))
            {
                ++j;
                if (j>m) j=1;
            }
            temp=sqrdist(con[i],con[j]);
            if (temp>ans)
                ans=temp;
        }
        return ans;
    }
    
    int n,m;
    int ans;
    
    int main()
    {
        scanf("%d",&n);
        rep(i,1,n) scanf("%d%d",&ori[i].x,&ori[i].y);
        m=Graham(n);
        ans=mindist(m);
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    2018-2019-2 20165333 《网络对抗技术》 Exp6 信息搜集与漏洞扫描
    2018-2019-2 20165333 《网络对抗技术》 Exp5:MSF基础应用
    2018-2019-2 网络对抗技术 20165333 Exp4 恶意代码分析
    2018-2019-2 网络对抗技术 20165333 Exp3 免杀原理与实践
    2018-2019-2 网络对抗技术 20165333 Exp2 后门原理与实践
    2018-2019-2 网络对抗技术 20165333 Exp1 PC平台逆向破解
    2018-2019-2 网络对抗week1 Kali安装 20165333陈国超
    第三次作业+105032014138
    第二次作业+105032014138
    实验三+138+牟平
  • 原文地址:https://www.cnblogs.com/terra/p/7245216.html
Copyright © 2020-2023  润新知