凸包,格拉汉扫除法
思想的话就不想写了
有兴趣的童鞋详见《算法艺术》以及以下的网址:
http://www.nocow.cn/index.php/Graham_Scan
http://www.nocow.cn/index.php/Fc_solution
下面给一个带注解的代码:
program liukee;
type lkj=record
x:double;
y:double;
end;
var
a:array[1..10000] of lkj;
s:array[0..10000] of longint;
temp:lkj;
top,i,n:longint;
ans,r:double;
function dis(a,b:lkj):double;
begin
exit(sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)));//这里为了保证精度,必须这么写
end;
function calc(a,b,c:lkj):double;//计算向量的叉
var
x1,y1,x2,y2:double;
begin
x1:=a.x-c.x;
x2:=b.x-c.x;
y1:=a.y-c.y;
y2:=b.y-c.y;
exit(x1*y2-x2*y1);
end;
procedure qsort(l,r:longint);//对点进行排序
var
mid,temp:lkj;
i,j:longint;
begin
i:=l;
j:=r;
mid:=a[(l+r)>>1];//可以随机化
repeat
while(calc(a[i],mid,a[1])>0)or((calc(a[i],mid,a[1])=0)and(dis(a[i],a[1])<dis(mid,a[1])))do inc(i);//逆时针
while(calc(a[j],mid,a[1])<0)or((calc(a[j],mid,a[1])=0)and(dis(a[j],a[1])>dis(mid,a[1])))do dec(j);
if i<=j then
begin
temp:=a[i];
a[i]:=a[j];
a[j]:=temp;
inc(i);
dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end;
begin
assign(input,'try.in');reset(input);
readln(n{,r});
randomize;
for i:=1 to n do
readln(a[i].x,a[i].y);
for i:=2 to n do//找到最下端的点
if (a[i].y<a[1].y)or((a[i].y=a[1].y)and(a[i].x<a[1].x))then
begin
temp:=a[i];
a[i]:=a[1];
a[1]:=temp;
end;
qsort(2,n);
top:=2;
s[1]:=1;
s[2]:=2;
for i:=3 to n do//压栈,操作,生成凸包
begin
while(top>1)and(calc(a[i],a[s[top]],a[s[top-1]])>0)do//不用打等于0因为这种共线情况已在之前的排序中处理了
dec(top);
inc(top);
s[top]:=i;
end;
//计算结果
ans:=0;
{ans:=ans+pi*2*r;}
ans:=ans+dis(a[s[top]],a[s[1]]);
for i:=1 to top-1 do
ans:=ans+dis(a[s[i]],a[s[i+1]]);
writeln(round(ans));
end.
浙公网安备 33010602011771号