hdu1392凸包求周长 graham 3种写法

来源:互联网 发布:用户数据分析发展方向 编辑:程序博客网 时间:2024/05/17 20:26

一开始用两边扫的过不去,后来自己加了初始化就过了,郁闷一晚上。。。

凸包求周长。。。

两边扫点

#include<iostream>#include<algorithm>#include<cmath>#define MAX 2000#define eps 1e-9using namespace std;struct points{    double x,y;};points p[MAX];int n,l,res[MAX],top;double mult(points sp,points ep,points op){    return (sp.x-op.x)*(ep.y-op.y)>=(ep.x-op.x)*(sp.y-op.y);}bool cmp(const points &a,const points &b){    if(a.y-b.y==eps)return a.x-b.x<eps;    return a.y-b.y<eps;    }void graham(){    int i,len;    top=1;    sort(p,p+n,cmp);    if(n==0)return; res[0]=0;    if(n==1)return; res[1]=1;    if(n==2)return; res[2]=2;    for(i=2;i<n;i++)    {        while(top && mult(p[i],p[res[top]],p[res[top-1]]))            top--;            res[++top]=i;    }    len=top;    res[++top]=n-2;    for(i=n-3;i>=0;i--)    {        while(top!=len && mult(p[i],p[res[top]],p[res[top-1]]))            top--;            res[++top]=i;    }}double dists(points aa,points bb){ return sqrt((aa.x-bb.x)*(aa.x-bb.x)+(aa.y-bb.y)*(aa.y-bb.y));}int main(){    while(scanf("%d",&n)!=EOF && n)    {        memset(p,0,sizeof(p));        memset(res,0,sizeof(res));        {            for(int i=0;i<n;i++)                scanf("%lf%lf",&p[i].x,&p[i].y);            if(n<2)printf("0.00\n");            else            if(n==2)printf("%.2lf\n",dists(p[0],p[1]));            else            {            graham();            double re=0;           /* for(int i=0;i<top;i++)            {                cout<<"..."<<p[res[i]].x<<"  "<<p[res[i]].y<<endl;            }*/            for(int i=0;i<top;i++)                re+=dists(p[res[i]],p[res[(i+1)%(top+1)]]);            printf("%.2lf\n",re);            }        }    }    return 0;    }

用tan来排序那么扫点只用1次,因为tan是单调的


#include<iostream>#include<algorithm>#include<cmath>#define MAX 1000#define eps 1e-12using namespace std;struct points{    double x,y;    double atan;};points p[MAX],res[MAX];int n,l,top;double mult(points sp,points ep,points op){    return (sp.x-op.x)*(ep.y-op.y)>=(ep.x-op.x)*(sp.y-op.y);}bool ral(points p1,points p2,points p3){     return (p3.x-p1.x)*(p2.y-p1.y)>=(p2.x-p1.x)*(p3.y-p1.y);}bool cmp(const points &a,const points &b){    if(a.y-b.y==eps||a.y-b.y==0)return a.x-b.x<eps;    return a.y-b.y<eps;   /* return a.y<b.y||(a.y==b.y&&a.x<b.x);*/    }int cmp2(points a,points b){     return a.atan<b.atan || ( a.atan==b.atan && a.x<b.x );}void graham(){    int i,len;    top=1;    sort(p,p+n,cmp);    /**/    p[0].atan=0;    for (int i=1;i<n;i++)    p[i].atan=atan2(p[i].y-p[0].y,p[i].x-p[0].x);    sort(p,p+n,cmp2);    /**/     /*    if(n==0)return; res[0]=0;    if(n==1)return; res[1]=1;    if(n==2)return; res[2]=2;*/    res[0]=p[0];    res[1]=p[1];    for(i=2;i<n;i++)    {        while(top && ral(res[top-1],res[top],p[i]))            top--;            res[++top]=p[i];    }    /*if(top>2 && ral(res[top-1],res[top],p[i]))    top--;        len=top;    res[++top]=n-2;    for(i=n-3;i>=0;i--)    {        while(top != len && mult(p[i],p[res[top]],p[res[top-1]]))            top--;        res[++top]=i;    }*/}double dists(points aa,points bb){ return sqrt((aa.x-bb.x)*(aa.x-bb.x)+(aa.y-bb.y)*(aa.y-bb.y));}int main(){    while(scanf("%d",&n)!=EOF && n)    {                    for(int i=0;i<n;i++)                scanf("%lf%lf",&p[i].x,&p[i].y);            if(n<2)printf("0.00\n");            else                if(n==2)printf("%.2lf\n",dists(p[0],p[1]));                else                {                    graham();                    double re=0.0;                /*for(int i=0;i<=top;i++)                    cout<<res[i].x<<"  "<<res[i].y<<endl;*/                    for(int i=0;i<=top;i++)                        re+=dists(res[i],res[(i+1)%(top+1)]);                    printf("%.2lf\n",re);                }            }    return 0;    }

还有一种网上的用极坐标交换的写法,标准模板


#include <iostream>#include <math.h>#define MaxNode 1000int stack[MaxNode];int top;struct TPoint{    int x;    int y;};TPoint point[MaxNode];void swap(TPoint point[], int i, int j){    TPoint tmp;    tmp = point[i];    point[i] = point[j];    point[j] = tmp;}double multi(TPoint p1, TPoint p2, TPoint p0){    return double(p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);}double distance(TPoint p1, TPoint p2){   return sqrt(double(p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));}//qsort的比较函数,如果要从小到大排序,则:参数1>参数2时,return1;int cmp(const void *a, const void *b){    TPoint *c = (TPoint *)a;    TPoint *d = (TPoint *)b;    double k = multi(*c, *d, point[0]);    if(k <= 0) return 1; //k<0说明c在d的逆时针方向,即相对于点p0,c的极角比d大    else return -1;  }void grahamScan(int n){    //Graham扫描求凸包    int u=0;        //将最左下的点调整到p[0]的位置    for(int i = 1;i <= n - 1;i++)    {        if((point[i].y < point[u].y) || (point[i].y == point[u].y && point[i].x < point[u].x))        u = i;         }    swap(point, 0, u);       //将p[1]到p[n - 1]按按极角排序,可采用快速排序    qsort(point + 1, n - 1, sizeof(point[0]), cmp);    for(int i = 0;i <= 2;i++) stack[i] = i;    top = 2;    for(int i = 3;i <= n - 1;i++)    {        while(multi(point[i], point[stack[top]], point[stack[top - 1]]) > 0)            top--;        top++;        stack[top] = i;    }}double length(int n){    //已知多边形各顶点的坐标,求其周长    double len;    int i;    len = 0;    for(i = 0;i <= n - 1;i++){        len += (distance(point[stack[i]], point[stack[(i + 1) % n]]));//别忘了模n(处理最后一个点和第一个点的距离)    }    return len;}int main(){    int i, n;    while(scanf("%d", &n) && n ){        for(i = 0;i < n;i++)        scanf("%d%d", &point[i].x, &point[i].y);        if(n < 2){            printf("0.00\n");            continue;              }        if(n == 2){            printf("%.2lf\n", distance(point[0], point[1]));            continue;        }        grahamScan(n);        printf("%.2lf\n", length(top + 1));           }    return 0;}