zoukankan      html  css  js  c++  java
  • (模板)graham扫描法、andrew算法求凸包

    题目链接:https://vjudge.net/problem/POJ-1113

    题意:简化下题意即求凸包的周长+2×PI×r。

    思路:用graham求凸包,模板是kuangbin的,算法复杂度O(nlogn)。

    AC code:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    
    const int maxn=1005;
    const double PI=acos(-1.0);
    
    struct Point{
        int x,y;
        Point():x(0),y(0){}
        Point(int x,int y):x(x),y(y){}
    }list[maxn];
    int stack[maxn],top;
    
    //计算叉积p0p1×p0p2
    int cross(Point p0,Point p1,Point p2){
        return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
    }
    //计算p1p2的距离
    double dis(Point p1,Point p2){
        return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
    }
    //极角排序函数,角度相同则距离小的在前面
    bool cmp(Point p1,Point p2){
        int tmp=cross(list[0],p1,p2);
        if(tmp>0) return true;
        else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
        else return false;
    }
    //输入,把最左下角放在list[0],并且进行极角排序 
    void init(int n){
        Point p0;
        scanf("%d%d",&list[0].x,&list[0].y);
        p0.x=list[0].x;
        p0.y=list[0].y;
        int k=0;
        for(int i=1;i<n;++i){
            scanf("%d%d",&list[i].x,&list[i].y);
            if((p0.y>list[i].y)||((p0.y==list[i].y)&&(p0.x>list[i].x))){
                p0.x=list[i].x;
                p0.y=list[i].y;
                k=i;
            }
        }
        list[k]=list[0];
        list[0]=p0;
        sort(list+1,list+n,cmp);
    }
    //graham扫描法求凸包,凸包顶点存在stack栈中
    //从栈底到栈顶一次是逆时针方向排列的
    //如果要求凸包的一条边有2个以上的点
    //那么要将while中的<=改成<
    //但这不能将最后一条边上的多个点保留
    //因为排序时将距离近的点排在前面
    //那么最后一条边上的点仅有距离最远的会被保留,其余的会被出栈
    //所以最后一条边需要特判
    //如果要求逆凸包的话需要改cmp,graham中的符号即可
    void graham(int n){ if(n==1){ top=0; stack[0]=0; return; } top=1; stack[0]=0; stack[1]=1; for(int i=2;i<n;++i){ while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) --top; stack[++top]=i; } } int main(){ int n,r; scanf("%d%d",&n,&r); init(n); graham(n); double res=2*PI*r; for(int i=0;i<top;++i) res+=dis(list[stack[i]],list[stack[i+1]]); res+=dis(list[stack[0]],list[stack[top]]); printf("%d ",(int)(res+0.5));
      int ans=0;
      //叉积求凸包面积
    //for(int i=0;i<top;++i)
            //ans+=cross(Point(0,0),list[stack[i]],list[stack[i+1]]);
       //ans+=cross(Point(0,0),list[stack[top]],list[stack[0]]);
       //ans/=2;
    return 0; }

    题目链接:https://www.luogu.com.cn/problem/P2742

    题意:求凸包的周长。

    思路:

      这里用andrew算法来求,该算法与graham的区别是排序方法不一样,这里按x坐标从左到右排序,x相同的按y坐标从下到上排序。下列程序展示先求下凸包,再求上凸包。复杂度O(nlogn),但据说比graham的复杂度小一点。

    AC code:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    using namespace std;
    
    const int maxn=1e5+5;
    
    struct Point{
        double x,y;
        Point(double xx=0,double yy=0):x(xx),y(yy){}
    };
    
    double cross(Point p0,Point p1,Point p2){
        return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
    }
    //排序方法不同
    bool cmp(Point a,Point b){
        if(a.x!=b.x) return a.x<b.x;
        return a.y<b.y; //y从小到大和从大到小都行
    }
    
    double dis(Point a,Point b){
        return sqrt((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y));
    }
    
    Point list[maxn],stk[maxn];
    int n,p;
    double ans;
    
    void andrew(){
        p=1;
        stk[0]=list[0],stk[1]=list[1];
        for(int i=2;i<n;++i){ //求下凸包
            while(p>0&&cross(stk[p-1],stk[p],list[i])<=0)
                --p;
            stk[++p]=list[i];
        }
        stk[++p]=list[n-2];
        for(int i=n-3;i>=0;--i){ //求上凸包
            while(p>0&&cross(stk[p-1],stk[p],list[i])<=0)
                --p;
            stk[++p]=list[i];
        }   //要注意栈尾和栈顶都是list[0]
    }
    
    int main(){
        scanf("%d",&n);
        for(int i=0;i<n;++i)
            scanf("%lf%lf",&list[i].x,&list[i].y);
        sort(list,list+n,cmp);
        andrew();
        for(int i=0;i<p;++i)
            ans+=dis(stk[i],stk[i+1]);
        printf("%.2f
    ",ans);
        return 0;
    }
  • 相关阅读:
    hdu4639 hehe ——斐波纳契数列,找规律
    codefoces round193a
    codeforces 192e
    abbyy cup a
    年中总结
    codeforces 192a
    codeforces 192b
    codeforces 192 c
    codeforces 192 D
    codeforces magic five --快速幂模
  • 原文地址:https://www.cnblogs.com/FrankChen831X/p/11824907.html
Copyright © 2011-2022 走看看