凸包,格拉汉扫除法

思想的话就不想写了

有兴趣的童鞋详见《算法艺术》以及以下的网址:

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.

posted @ 2010-11-08 16:57  liukee  阅读(273)  评论(0编辑  收藏  举报