hdu1392凸包求周长 graham 3种写法

本文介绍了几种实现凸包算法的方法,并演示了如何利用这些算法计算凸包的周长。通过两种不同的扫描策略(两次扫描和一次扫描),文章详细展示了如何使用C++进行编程实现,包括初始化、排序、点的比较等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

凸包求周长。。。

两边扫点

#include<iostream>
#include<algorithm>
#include<cmath>
#define MAX 2000
#define eps 1e-9
using 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-12
using 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 1000

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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值