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