1. 程式人生 > >凸包——Graham-Scan演算法

凸包——Graham-Scan演算法

Graham-Scan演算法是一種靈活的凸包演算法,時間複雜度是O(nlogn) 演算法細節: 1. 選出最左下角的點(排序:x最小,其次是y最小) 2. 其餘點按極角排序,在極角相等的情況下距離極點(p[0])最近的優先 3. 用一個棧(陣列)儲存凸包上的點,先把p[0],p[1]壓入棧。 4. 掃描每一個點,用叉積判斷新點和棧頂頭兩個點形成的拐向。順時針就彈出棧頂元素,繼續判斷。否則壓入新點p[i] (判斷的前提是棧內已經壓入了兩個點) 5. 最終棧內元素就是凸包點。
附圖說明(接下來看圖,用心感受):

現在用Graha-Scan演算法做,更加高效:

POJ 1113 Wall

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
const double eps=1e-7,Pi=3.1415926;
struct point{
    int x,y;
}p[1005],ans[1005];

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);
}

double dis(point a,point b){
    return sqrt(1.0*(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

int cmp1(point p1,point p2){
    return p1.x<p2.x||(p1.x==p2.x&&p1.y<p2.y);
}

int cmp2(point p1,point p2){
    int c1=cross(p[0],p1,p2);  //tp,p1),c2=cross(p[0],tp,p2);
    if(c1==0){
        return dis(p1,p[0])<dis(p2,p[0]);
    }
    return c1>0;
}

int top;
void convex(int n){
    top=0;
    sort(p,p+n,cmp1);
    sort(p+1,p+n,cmp2);
    ans[top++]=p[0];
    ans[top++]=p[1];
    for(int i=2;i<n;i++){
        if(cross(ans[top-2],ans[top-1],p[i])>0) ans[top++]=p[i];
        else {
            top--;  
            while(top>=2&&cross(ans[top-2],ans[top-1],p[i])<=0) top--;
            ans[top++]=p[i];
        }
    }
    ans[top++]=p[0];
}
int main()
{
    //freopen("cin.txt","r",stdin);
    int n,l;
    while(cin>>n>>l){
        for(int i=0;i<n;i++){
            scanf("%d%d",&p[i].x,&p[i].y);
        }
        convex(n);
        double sum=0;
        for(int i=0;i<top-1;i++){
            sum=sum+dis(ans[i],ans[i+1]); // this is ans[] , not p[], fucos on your var
        }
        sum=sum+2*Pi*l;
        printf("%d\n",int(sum+0.5));
    }
    return 0;
}