小马承包了一个果园,想修一个围栏,但是不希望砍掉任何的果树。对于给出的所有的果树的坐标,计算一下最小的围住所有的果树的围栏的长度。
输入数据的第一行包括一个整数 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扫描法