计蒜客——圈果树

传送门

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

输入数据的第一行包括一个整数 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

本题特别注意n<3的情况

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 10005;
struct spe
{
    double x,y;
}A[maxn],S[maxn];
bool cmp(spe a,spe b)
{
    if(a.x!=b.x)
        return a.x<b.x;
    return a.y<b.y;
}
double Xmulti(spe a,spe b,spe c)//点积,ab向量*ac向量
{
    return ((b.y-a.y)*(c.x-a.x)-(b.x-a.x)*(c.y-a.y));
}
double dis(spe a,spe b)
{//距离
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int ConvexHull(spe *A,int n,spe *S)
{
    int m = 0;
    for(int i = 0;i < n; i++)
    {
        while(m > 1&&Xmulti(S[m-2],A[i],S[m-1])<=0)
            m--;
        S[m++] = A[i];//更新点
    }
    //顺时针遍历一遍
    int k = m;
    for(int i=n-2; i>=0; i--)
    {
        while(m>k && Xmulti(S[m-2],A[i],S[m-1])<=0)
            m--;
        S[m++] = A[i];
    }
    if(n > 1)
        m--;
    return m;
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i =0; i < n; i++)
        scanf("%lf%lf",&A[i].x,&A[i].y);
    if(n <= 1)
        printf("0.00\n");
    else if(n == 2)
        {
            printf("%.2lf\n",dis(A[0],A[1]));
        }
        else
        {
            sort(A,A+n,cmp);
            int cnt = ConvexHull(A, n, S);
            double sum = dis(S[0],S[cnt-1]);
            for(int i = 0; i < cnt-1; i++)
                sum+=dis(S[i],S[i+1]);
            printf("%.2lf\n",sum);
        }
    return 0;
}

我觉得凸包(百度百科)解释的很详细,可以先看看,再来做,这只是其中一种算法:Graham扫描法

猜你喜欢

转载自blog.csdn.net/Nothing_227/article/details/81625278