【Description】
小徐是USACO中国区的奶牛代理商,专门销售质优价廉的“FJ”牌奶牛。
有一天,她正在卖奶牛,突然觉得很孤单,想把她的朋友接来。
可这要花一大笔钱。
她有N个牛棚,想让你帮她重新围一块地,包含所有牛棚,且是凸多边形(否则奶牛会撞墙角)
她现在经济很困难,不用你关心省下的地能卖多少钱,只要能让围栏最短,花最少的钱。
请你计算围栏的最短长度。
【Input】
N
每个牛棚的坐标(整数)
【Output】
最短长度(保留2位小数)
【Sample Input】
4
0 3
3 0
0 0
1 1
【Sample Output】
10.24
【Data Size and Hint】
N≤1000
|X|,|Y|≤500
【Solution】
题目是形象地告诉你求一个能包进所有点的凸包周长。
具体方法参考LRJ黑书上的叉积部分和白书上Andrew算法部分。
参考代码如下:
type point = record
x,y:longint;
end;
var n,m,i:longint;
ans:double;
p:array[0..1010] of point;
stack:array[0..1010] of point;
procedure init; //读入
var i:longint;
begin
readln(n);
for i:=1 to n do readln(p[i].x,p[i].y);
end;
procedure qsort(l,r:longint); //按x第一关键字,y第二关键字排序
var i,j,mid,mid2:longint;
tmp:point;
begin
i:=l; j:=r; mid:=p[(i+j) shr 1].x; mid2:=p[(i+j) shr 1].y;
repeat
while (p[i].x<mid) or ((p[i].x=mid) and (p[i].y<mid2)) do inc(i);
while (p[j].x>mid) or ((p[j].x=mid) and (p[j].y>mid2)) do dec(j);
if i<=j then begin
tmp:=p[i]; p[i]:=p[j]; p[j]:=tmp;
inc(i); dec(j);
end;
until i>j;
if i<r then qsort(i,r);
if l<j then qsort(l,j);
end;
function Cross(a,b:point):longint; //求叉积
begin
exit(a.x*b.y-b.x*a.y);
end;
function minus(a,b:point):point; //求向量差
begin
minus.x:=a.x-b.x; minus.y:=a.y-b.y;
end;
procedure ConvexHull; //Andrew求凸包
var i,k:longint;
begin
m:=1;
fillchar(stack,sizeof(stack),0);
for i:=1 to n do begin
while (m>2) and (Cross(minus(stack[m-1],stack[m-2]),
minus(p[i],stack[m-2]))<=0)
do dec(m);
stack[m]:=p[i]; inc(m);
end;
k:=m;
for i:=n-1 downto 1 do begin
while (m>k) and (Cross(minus(stack[m-1],stack[m-2]),
minus(p[i],stack[m-2]))<=0)
do dec(m);
stack[m]:=p[i]; inc(m);
end;
end;
function calc(a,b:point):double; //计算两点间距离
begin
exit(sqrt(sqr(a.x-b.x)+sqr(a.y-b.y)));
end;
procedure print; //输出周长
var i:longint;
begin
for i:=2 to m-1 do
ans:=ans+calc(stack[i],stack[i-1]);
writeln(ans:0:2);
end;
begin
init;
qsort(1,n);
ConvexHull;
print;
end.