Description

农夫约翰想要建造一个围栏用来围住他的奶牛,可是他资金匮乏。他建造的围栏必须包括他的奶牛喜欢吃草的所有地点。对于给出的这些地点的坐标,计算最短的能够围住这些点的围栏的长度。

Input

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

Output

输出必须包括一个实数,表示必须的围栏的长度。答案保留两位小数。

Sample Input

44 84 125 9.37 8

Sample Output

12.00

Source

USACO


题意:给你n个点,让你用栅栏把这n个点圈起来,问圈住n个点的最小长度。

就是要求你求维护一个凸包,光荣的成为了一道凸包的裸题。

我才不会告诉你这是我第一个不看任何模板自己写出的算法呢。

我求凸包用的是卷包裹法。

卷包裹法:http://blog.csdn.net/lzr010506/article/details/50775301

代码:

#include <bits/stdc++.h>
using namespace std;
struct Point
{
	double x, y;
}a[10010];
int n, P, b[10010], tb[10010];

inline double sq(double x)
{
	return x * x;
}

inline double cj(Point a, Point b, Point c)//求向量 a->b a->c 的叉积 
{
	return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
}
//b.x-a.x b.y-a.y  c.x-a.x c.y-a.y 
inline double dis(Point a, Point b)
{
	return sqrt( sq(b.x - a.x) + sq(b.y - a.y) );
}

int main()
{
	scanf("%d",&n);
	double px = 1000010.0, py = 1000010.0;
	for(int i = 1; i <= n; i ++)
	{
		scanf("%lf%lf",&a[i].x, &a[i].y);
		if(px > a[i].x) P = i, px = a[i].x, py = a[i].y;
		else 
			if(px == a[i].x) 
				if(py > a[i].y) P = i, py = a[i].y;
	}
	if(n == 1) 
	{
		printf("0.00");
		return 0;
	}
	if(n == 2)
	{
		printf("%.2lf",dis(a[1], a[2]));
		return 0;
	}
	
	int cnt = 1;
	Point now;
	now = a[P];
	tb[cnt] = P;
	while(now.x != a[P].x || now.y != a[P].y || cnt == 1) 
	{
		Point p;
		int pp;
		for(int i = 1; i <= n; i ++)
			if(b[i] == 0)
			{
				p = a[i];
				pp = i;
				break;
			}
		for(int i = 1; i <= n; i ++)
		{
			if(b[i] == 1) continue;
			double now_cj = cj(now, p, a[i]);
			if(now_cj == 0) 
			{
				double dp = dis(now, p);
				double da = dis(now, a[i]);
				if(da > dp) p = a[i],pp = i;
				continue; 
			}
			if(now_cj < 0)
				p = a[i],pp = i;
		}
		tb[++ cnt] = pp;
		now = p;
		b[pp] = 1;
	}
	double ans = 0.00;
	for(int i = 2; i <= cnt; i ++)
		ans += dis( a[tb[i]], a[tb[i - 1]] );
	printf("%.2lf", ans);
	return 0;
}