凸包,格拉汉扫除法
思想的话就不想写了
有兴趣的童鞋详见《算法艺术》以及以下的网址:
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.