计算几何 usaco Fencing the Cows 圈奶牛

来源:互联网 发布:家用网络哪家好 编辑:程序博客网 时间:2024/05/01 22:05

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;}


0 0