您的位置:首页 > Web前端

JZOJ1312.【USACO题库】5.1.1 Fencing the Cows圈奶牛

2017-07-06 09:11 337 查看

problem

题目描述

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

PROGRAM NAME: fc

INPUT FORMAT

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

SAMPLE INPUT (file fc.in)

4

4 8

4 12

5 9.3

7 8

OUTPUT FORMAT

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

SAMPLE OUTPUT (file fc.out)

12.00

输入

输出

样例输入

样例输出

数据范围限制

analysis

由于本人心血来潮我重新写了另一篇排版更好看更好懂的凸包blog

凸包详解:http://blog.csdn.net
10755
/enjoy_pascal/article/details/78397028


好,看完了吗?理解了吗?

所以,这道题完全就是一道凸包裸题

我们用graham把凸包上的点全部求出,再计算凸包中两两相邻的点的距离和就可以了

code

新学的OIers建议别直接看代码,还是尽量手撸,自己理解理解

type
point=record
x,y:extended;
end;
var
f:array[0..10000]of point;
angle:array[0..10000]of
record
x,y,value,dis:extended;
end;//x,y坐标,value角度,dis与原点距离
stack:array[0..10000]of longint;
row,rank:extended;
n,i,j,tot,up:longint;
ans:extended;
function judge(ax,ay,bx,by,cx,cy:extended):extended;
begin//判断点是否在直线左侧
exit(ax*by+cx*ay+bx*cy-cx*by-bx*ay-ax*cy);
end;
function arccot(xx,yy:extended):extended;
begin//返回一个点连原点与x轴正半轴的夹角
if yy=0 then exit(0);
if xx=0 then exit(90);
arccot:=arctan(yy/xx)*180/pi;//计算几何,这里用pascal自带的三角函数arctan
if xx<0 then arccot:=arccot+180;
end;
procedure qsort(l,r:longint);
var//快排,不解释
i,j:longint;
mid,mid1:extended;
begin
i:=l;
j:=r;
mid:=angle[(l+r)shr 1].value;
mid1:=angle[(l+r)shr 1].dis;
repeat
while (angle[i].value<mid)or(angle[i].value=mid)and(angle[i].dis<mid1)do inc(i);
while (angle[j].value>mid)or(angle[j].value=mid)and(angle[j].dis>mid1)do dec(j);
if i<=j then
begin
angle[0]:=angle[i];
angle[i]:=angle[j];
angle[j]:=angle[0];
inc(i);
dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end;
begin
readln(n);
rank:=maxlongint;

for i:=1 to n do
with f[i] do
begin
readln(x,y);
if y<rank then
begin
row:=x;
rank:=y;
end;//记录最底下的点的行列值
end;
for i:=1 to n do
with f[i] do
begin
x:=x-row;
y:=y-rank;
end;//把所有点平移一下,使没有点会在三四象限内
tot:=1;
for i:=1 to n do
with f[i] do
if (x<>0)or(y<>0) then
begin
inc(tot);
angle[tot].value:=arccot(x,y);
angle[tot].x:=x;
angle[tot].y:=y;
angle[tot].dis:=sqrt(x*x+y*y);
end;
qsort(2,n);//按角度为第一关键字、距离为第二关键字排序
up:=2;
stack[1]:=1;
stack[2]:=2;
for i:=3 to n do
begin
while judge(angle[stack[up-1]].x,angle[stack[up-1]].y,angle[stack[up]].x,angle[stack[up]].y,angle[i].x,angle[i].y)<0 do dec(up);//判断当前点是否满足要求
inc(up);
stack[up]:=i;//入栈
end;
ans:=0;
stack[up+1]:=stack[1];
for i:=1 to up do
ans:=ans+sqrt(sqr(angle[stack[i]].x-angle[stack[i+1]].x)+sqr(angle[stack[i]].y-angle[stack[i+1]].y));
writeln(ans:0:2);//统计凸包上两两相邻的点的距离,输出
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: