1670: [Usaco2006 Oct]Building the Moat护城河的挖掘

1670: [Usaco2006 Oct]Building the Moat护城河的挖掘

Time Limit: 3 Sec   Memory Limit: 64 MB
Submit: 304   Solved: 221
[ Submit][ Status][ Discuss]

Description

为了防止口渴的食蚁兽进入他的农场,Farmer John决定在他的农场周围挖一条护城河。农场里一共有N(8<=N<=5,000)股泉水,并且,护城河总是笔直地连接在河道上的相邻的两股泉水。护城河必须能保护所有的泉水,也就是说,能包围所有的泉水。泉水一定在护城河的内部,或者恰好在河道上。当然,护城河构成一个封闭的环。 挖护城河是一项昂贵的工程,于是,节约的FJ希望护城河的总长度尽量小。请你写个程序计算一下,在满足需求的条件下,护城河的总长最小是多少。 所有泉水的坐标都在范围为(1..10,000,000,1..10,000,000)的整点上,一股泉水对应着一个唯一确定的坐标。并且,任意三股泉水都不在一条直线上。 以下是一幅包含20股泉水的地图,泉水用"*"表示

1670: [Usaco2006 Oct]Building the Moat护城河的挖掘_第1张图片
图中的直线,为护城河的最优挖掘方案,即能围住所有泉水的最短路线。 路线从左上角起,经过泉水的坐标依次是:(18,0),(6,-6),(0,-5),(-3,-3),(-17,0),(-7,7),(0,4),(3,3)。绕行一周的路径总长为70.8700576850888(...)。答案只需要保留两位小数,于是输出是70.87。

Input

* 第1行: 一个整数,N * 第2..N+1行: 每行包含2个用空格隔开的整数,x[i]和y[i],即第i股泉水的位 置坐标

Output

* 第1行: 输出一个数字,表示满足条件的护城河的最短长度。保留两位小数

Sample Input

20
2 10
3 7
22 15
12 11
20 3
28 9
1 12
9 3
14 14
25 6
8 1
25 1
28 4
24 12
4 15
13 5
26 5
21 11
24 4
1 8

Sample Output

70.87

HINT

Source

凸包 卡壳

 

 

果然刚上高一的我就是弱呀。。。凸包学了1h+(主要是理解向量计算。。。。)

以左下角为(0,0),每个点都以(x,y)的方法表示,那么每个单位就可以表示那个点或者是起点到它的向量。。

向量是有运算法则的。。。。。。。。。。。。。。。。。。

本题使用Andrew算法,先将所有点按照x从小到大排序,对于x相同的再按y从小到大排序

先将一开始的两个点扔进凸包,然后一个个点去找,如果当前点与上个点的向量在当前路径右侧,

则删除路径上的点直到当前点在当前路径的左侧,反着再来一遍

复杂度O(nlogn)

用叉积来判断两个向量的位置关系(xA*yB-xB*yA)。。。

 

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

const int maxn = 5e3 + 50;
typedef double DB;

struct P{
	int x,y;
	P operator - (const P &b)
	{
		return (P) {x - b.x,y - b.y};
	}
	bool operator < (const P &b) const{
		if (x < b.x) return 1;
		if (x > b.x) return 0;
		return y < b.y;
	}
	bool operator != (const P &b) const{
		return x != b.x || y != b.y;
	}
}poi[maxn],edgs[4*maxn]; 

int Cross (P A,P B)
{
	return 1LL*A.x * B.y - 1LL*A.y * B.x;
}

DB det (P x,P y)
{
	long long A = x.x - y.x;
	long long B = x.y - y.y;
	return sqrt ((A*A) + (B*B));
}

int n,i,j,cur = 1;

int main()
{
	#ifdef YZY
		freopen("yzy.txt","r",stdin);
	#endif
	cin >> n;
	for (i = 1; i <= n; i++) scanf("%d%d",&poi[i].x,&poi[i].y);
	sort (poi + 1,poi + n + 1);
	for (i = 2; i <= n; i++)
	  if (poi[i] != poi[i-1])
	    poi[++cur] = poi[i];
	int Siz = 0;
	for (i = 1; i <= cur; i++)
	{
		while (Siz > 1 && Cross(edgs[Siz] - edgs[Siz-1],poi[i] - edgs[Siz-1]) <= 0) Siz--;
		edgs[++Siz] = poi[i];
	}
	int down = Siz;
	for (i = cur - 1; i > 0; i--)
	{
		while (Siz > down && Cross(edgs[Siz] - edgs[Siz-1],poi[i] - edgs[Siz-1]) <= 0) Siz--;
		edgs[++Siz] = poi[i];
	}
	DB ans = 0;
	for (i = 1; i < Siz; i++) ans += det (edgs[i],edgs[i + 1]);
	printf("%.2lf",ans);
	return 0;
}


 

你可能感兴趣的:(1670: [Usaco2006 Oct]Building the Moat护城河的挖掘)