hdu 1392 Surround the Trees(凸包模版)

来源:互联网 发布:程序员找工作步骤 编辑:程序博客网 时间:2024/05/19 23:28

写得有点圡

水平排序版本:

#include <cmath>#include <cstdio>#include <algorithm>#include <iostream>using namespace std;struct point{    double x,y;    bool operator < (point &a){        return y<a.y || (y == a.y && x<a.x);    }};bool mult(point &sp,point &ep,point &op){    return (sp.x-op.x)*(ep.y-op.y)        >=(ep.x-op.x)*(sp.y-op.y);}double dist(point &a,point &b){    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}double graham(point *pnt,int n,point res[]){    int i,len,k=0,top=1;    sort(pnt,pnt+n);    if(n==0) return 0; res[0]=pnt[0];    if(n==1) return 0; res[1]=pnt[1];    if(n==2) return dist(pnt[0],pnt[1]); res[2]=pnt[2];    for(i=2;i<n;i++){        while(top && mult(pnt[i],res[top],res[top-1])) //左转退栈,上凸包            top--;        res[++top]=pnt[i];    }    len=top;    res[++top]=pnt[n-2];    for(i=n-3;i>=0;i--){        while(top!=len && mult(pnt[i],res[top],res[top-1]))//下凸包。            top--;        res[++top]=pnt[i];    }    double area=0;    for(i=1;i<=top;i++){        area+=dist(res[i],res[(i+1)>top?1:(i+1)]);    }        return area;}int main(){    int n;    point pnt[105],res[105];    while(scanf("%d",&n) && n){        for(int i=0;i<n;i++)            scanf("%lf %lf",&pnt[i].x,&pnt[i].y);        printf("%.2lf\n",graham(pnt,n,res));    }    return 0;}


极角排序版本:

#include <cstdio>#include <cstring>#include <iostream>#include <cmath>#include <algorithm>using namespace std;typedef struct point{double x,y;bool operator < (point &a){return y<a.y || (y==a.y && x<a.y); //重载小于号}}p;p temp;double dist(p &a,p &b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}bool cmp(p &a,p &b){double xmt=(a.x-temp.x)*(b.y-temp.y)-(b.x-temp.x)*(a.y-temp.y);if(xmt)//向量不共线就按逆时针旋转return xmt>0;return dist(a,temp)>dist(b,temp);//向量共线取最长的。}bool xmult(p& a,p& b,p& t){ //叉乘大于0 往左转,叉乘小于0往右转,等于0向量共线return (a.x-t.x)*(b.y-t.y)>=(b.x-t.x)*(a.y-t.y);}void swap(p& a,p &b){temp=b;b=a;a=temp;}double graham(p *pnt,int n,p *res){ //Graham扫描法if(n==1) return 0; if(n==2) return dist(pnt[0],pnt[1]); int top=-1;for(int i=0;i<n;i++){while(top>1 && xmult(pnt[i],res[top],res[top-1]))top--;res[++top] = pnt[i];}double dis=0;for(int j=0;j<=top;j++){dis+=dist(res[j],res[(j+1)%(top+1)]);}return dis;}int main(){int n;p pnt[105],res[105];while(scanf("%d",&n) && n){int t;for(int i=0;i<n;i++){scanf("%lf %lf",&pnt[i].x,&pnt[i].y);if(!i || pnt[i]<pnt[t]) //找出最小y坐标值并且最靠左的点t=i;}swap(pnt[0],pnt[t]);sort(pnt+1,pnt+n,cmp);printf("%.2lf\n",graham(pnt,n,res));}return 0;}