您的位置:首页 > 其它

[Poj 2187]计算几何之凸包(三) {旋转卡壳初步}

2011-04-03 22:19 573 查看
{

上一节介绍了凸包的高效算法

和一个最远点对的应用

这一段将更好的解决最远点对问题

}

(若不做特殊说明 下文讨论的问题均是在欧氏空间

若不做特殊说明 下文中距离均是指空间中欧氏距离)

==============================

一.简单枚举算法的不足

上一次介绍了一个基本的求平面最远点对的算法

即先求点集的凸包 然后枚举凸包上的点来求最远点集

这是利用了凸包上的点相比 点集中的点 一般是很少的 平均情况很好 并且我们也能AC这个问题

但是这是有局限性的 当凸包上的点达到O(N)的级别时 凸包的优化作用就不存在了

不过我们还要考虑到 凸包还起了对凸包上点集排序的作用

凸包有很多的优美的性质 我们可以加以利用 以得到更加高效的算法

旋转卡壳算法就是利用凸包特性的一类解决问题的方法

==============================

二.旋转卡壳算法

旋转卡(qiǎ)壳算法(Rotating Calipers Algorithm):

是解决一些与凸包有关问题的有效算法 就像一对卡壳卡住凸包旋转而得名

Every time one blade of the caliper lies flat against an edge of the polygon, it forms an antipodal pair
with the point or edge touching the opposite blade. It turns out that
the complete "rotation" of the caliper around the polygon detects all
antipodal pairs and may be carried out in O(n) time.

http://en.wikipedia.org/wiki/Rotating_calipers

Maxd

{$inline on}
{$optimization on}
const    maxn=50000;
type    point=record x,y:longint; end;
var    n,i,x,m,ans,j:longint;
ch,p:array[1..maxn+1]of point;
s:array[1..maxn]of longint;
function cross(a,b,c:point):longint; inline;
begin
cross:=(b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
end;
function dist(a,b:point):longint; inline;
begin
dist:=sqr(a.x-b.x)+sqr(a.y-b.y);
end;
function cmp(a,b:point):boolean; inline;
begin
cmp:=(a.x<b.x)or(a.x=b.x)and(a.y<b.y);
end;
function max(a,b:longint):longint;
begin
if a>b then max:=a else max:=b;
end;
procedure swap(a,b:longint); inline;
var    x:point;
begin
x:=p[a]; p[a]:=p[b]; p[b]:=x;
end;
procedure hull(l,r:longint; a,b:point);
var    x,i,j,k:longint;
y:point;
begin
x:=l; y:=p[l];
for k:=l to r do
if (s[x]<s[k])or(s[x]=s[k])and(cmp(y,p[k]))
then begin x:=k; y:=p[k]; end;
i:=l-1; j:=r+1;
for k:=l to r do
begin
inc(i); s[i]:=cross(p[k],a,y);
if s[i]>0 then swap(i,k) else dec(i);
end;
for k:=r downto l do
begin
dec(j); s[j]:=cross(p[k],y,b);
if s[j]>0 then swap(j,k) else inc(j);
end;
if l<=i then hull(l,i,a,y);
inc(m); ch[m]:=y;
if j<=r then hull(j,r,y,b);
end;
begin
assign(input,'Maxd.in'); reset(input);
assign(output,'Maxd.out'); rewrite(output);
readln(n);
for i:=1 to n do
begin
readln(p[i].x,p[i].y);
if (x=0)or cmp(p[i],p[x]) then x:=i;
end;
swap(1,x);
m:=1; ch[1]:=p[1]; hull(2,n,p[1],p[1]);
ch[m+1]:=ch[1]; j:=2; ans:=0;
for i:=1 to m do
begin
while cross(ch[i],ch[j],ch[i+1])<cross(ch[i],ch[j+1],ch[i+1]) do
begin inc(j); if j>m then j:=1; end;
ans:=max(ans,dist(ch[i],ch[j]));
end;
writeln(ans);
close(input); close(output);
end.


下一节介绍旋转卡壳的更多应用

之后开始介绍一点3D凸包
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: