计蒜客47——圈果树(二维凸包)

传送门


小马承包了一个果园,想修一个围栏,但是不希望砍掉任何的果树。对于给出的所有的果树的坐标,计算一下最小的围住所有的果树的围栏的长度。

输入数据的第一行包括一个整数 N(0≤ N ≤10,000)表示农夫约翰想要围住的放牧点的数目。接下来 N 行,每行由两个由空格分隔的实数组成,Xi 和 Yi,对应平面上的放牧点坐标(-1,000,000 ≤ Xi,Yi ≤ 1,000,000)。数字用小数表示。

输出包括一个实数,表示必须的围栏的长度(保留两位有效小数)


样例输入

4 
4 8
4 12
5 9.3
7 8

样例输出
12.00


解题思路:

直接计算一个二维凸包,然后计算凸包上相邻两两点的距离,然后加和就是周长。

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;
const double INF = 1e18+5;
const int MAXN = 1e4 + 5;
const double eps = 1e-10;
const double PI = acos(-1.0);
int double_cmp(double x)
{
    if(fabs(x) < eps)
        return 0;
    if(x > 0)
        return 1;
    return -1;
}

struct Point
{
    double x, y;
    int id;
    Point() {}
    Point (double _x, double _y, int i):x(_x),y(_y),id(i) {}
    bool operator <(const struct Point &tmp)const
    {
        if(double_cmp(x-tmp.x) == 0)
            return double_cmp(y-tmp.y) < 0;
        return double_cmp(x-tmp.x) < 0;
    }
    bool operator == (const struct Point &tmp)const
    {
        return double_cmp(x-tmp.x)==0&&double_cmp(y-tmp.y)==0;
    }
} p[MAXN],st[MAXN];
bool cmp(const Point& p1, const Point& p2)
{
    return atan2(p1.y, p1.x) < atan2(p2.y, p2.x);
}
double XMulti(Point a, Point b, Point c)///ac X ab
{
    return (c.x-a.x)*(b.y-a.y) - (b.x-a.x)*(c.y-a.y);
}

double dis(Point a, Point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}
double dis2(Point a, Point b)
{
    return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);
}
double dot(Point a, Point b, Point c)///点积 ab . ac
{
    double s1 = b.x-a.x;
    double t1 = b.y-a.y;
    double s2 = c.x-a.x;
    double t2 = c.y-a.y;
    return s1*s2 + t1*t2;
}

int ConvexHull(Point *p, int n, Point *st)///凸包
{
    sort(p, p+n);
    n = unique(p, p+n)-p;///去重
    int m = 0;
    for(int i=0; i<n; i++)
    {
        while(m>1 && XMulti(st[m-2],p[i],st[m-1])<=0)
            m--;
        st[m++] = p[i];
    }
    int k = m;
    for(int i=n-2; i>=0; i--)
    {
        while(m>k && XMulti(st[m-2],p[i],st[m-1])<=0)
            m--;
        st[m++] = p[i];
    }
    if(n > 1)
        m--;
    return m;
}
int main(){
    int n;
    while(~scanf("%d",&n)){
        for(int i=0; i<n; i++) scanf("%lf%lf",&p[i].x, &p[i].y);
        int cnt = ConvexHull(p, n, st);
        double sum = dis(st[0],st[cnt-1]);
        for(int i=0; i<cnt-1; i++)
            sum += dis(st[i], st[i+1]);
        printf("%.2f\n",sum);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值