CodeVS1298 凸包周长 解题报告【计算几何】【凸包】

题目描述 Description
给出平面上n个点,求出这n个点形成的凸包的周长。
凸包的定义:能覆盖住这个n个点的最小凸多边形。
输入描述 Input Description
第一行一个整数n,接下来n行,每行两个整数x和y,表示一个点的坐标。
数据范围 1 <= n <= 100000
-10000<=x,y<=10000
输出描述 Output Description
一行一个实数,表示凸包周长,保留一位小数.
样例输入 Sample Input
5
0 0
2 2
0 2
2 0
1 1
样例输出 Sample Output
8.0
解题报告
首先我们要解决存储问题,由于凸包的周长需要算第一个点和最后一个点间的距离,所以不能用vector存储,只能用数组来。
代码如下:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cstdlib>
#define NAME ""
#define Point Vector
using namespace std;
const double eps=1e-8;
const int N=100000;
struct Vector
{
    double x,y;
    double len(){return sqrt(x*x+y*y);}
    double ang(){return atan2(y,x);}
    Vector(int a=.0,int b=.0):x(a),y(b){}
    Vector operator+(const Vector &s)const{return Vector(x+s.x,y+s.y);}
    Vector operator-(const Vector &s)const{return Vector(x-s.x,y-s.y);}
    Vector operator*(int s)const{return Vector(x*s,y*s);}
    Vector operator/(int s)const{return Vector(x/s,y/s);}
    bool operator<(const Point &s)const
    {
        if(s.x==x)return y<s.y;
        else return x<s.x;
    }
}p[N+5],ch[N+5];
double dis(Point a,Point b)
{
    Point c=b-a;
    return c.len();
}
double cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;}//向量叉积 
int sign(double a){return a>eps?1:(a<-eps?-1:0);}
bool onleft(Point a,Point b,Point p)
{
    return sign(cross(b-a,p-a))>0;
}
double ComvexHull(Point* p,int n,Point* ch)
{
    sort(p+1,p+n+1);
    int m=0;
    for(int i=1;i<=n;++i)
    {
        while(m>1&&cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--;
        ch[m++]=p[i];
    }
    int k=m;
    for(int i=n-1;i>=1;--i)
    {
        while(m>k&&cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--;
        ch[m++]=p[i];
    }
    if(n>1) m--;
    double c=dis(ch[1],ch[m]);
    for(int i=1;i<m;++i) c+=dis(ch[i],ch[i+1]);
    return c;
}
int n;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        double x,y;
        scanf("%lf%lf",&x,&y);
        p[i]=Point(x,y);
    }
    printf("%.1lf",ComvexHull(p,n,ch));
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值