vijos p1012题解
弄懂求2维平面最近点对的方法就很简单了。
求最近点对大致如下:
1.以x,y坐标排序,先排x,再y
2.再for i:=1.. n 一遍,找到相邻点之间的距离,以找出相邻点间最短距离min(以便后面的剪枝)
3.分治,即折半查找。
分为两个点集X,Y,设最近点对为{A,B},有可能有3种情况
(1)A,B均在X。(2)A,B均在Y。(3)A,B分别在X与Y中
对于(1)(2),继续分治;对于(3),则以A+B的中间点xm,ym作为轴,找出所有|xi-xm|<min的点进行比较,更新min。
4.输出min
代码如下:
type
point=record
x,y:real;
end;
var
n:longint;
rd:real;
city,r:array[0..100000]of point;
procedure swap(var a,b:real);
var
t:real;
begin
t:=a;a:=b;b:=t;
end;
procedure qsort(l,r:longint);
var
i,j:longint;m:point;
begin
i:=l;j:=r;
m:=city[random(j-i)+i];
repeat
while (city[i].x<m.x)or((city[i].x=m.x)and(city[i].y<m.y)) do inc(i);
while (city[j].x>m.x)or((city[j].x=m.x)and(city[j].y>m.y)) do dec(j);
if i<=j then
begin
swap(city[i].x,city[j].x);
swap(city[i].y,city[j].y);
inc(i);dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end;
function dis(a,b:point):real;
begin
dis:=sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
end;
function min(a,b:real):real;
begin
if a<b then exit(a) else exit(b);
end;
procedure init;
var
i,j:longint;
begin
readln(n);
for i:=1 to n do
with city[i] do
readln(x,y);
qsort(1,n);
rd:=1e10;
for i:=2 to n do rd:=min(rd,dis(city[i-1],city[i]));
end;
procedure work(l,r:longint);
var
i,j,m:longint;d:real;
begin
m:=(l+r) shr 1;
i:=m;
while (l<=i)and(city[m].x-city[i].x<rd) do
begin
j:=m+1;
while (j<=r) and( city[j].x-city[m].x<rd) do
begin
rd:=min(rd,dis(city[i],city[j]));
inc(j);
end;
dec(i);
end;
end;
procedure find(l,r:longint);
var
i,j,t,k,h,mid:longint;d:real;
begin
if l=r then exit;
if l+1=r then
begin
rd:=min(rd,dis(city[l],city[r]));
end;
work(l,r);
mid:=(l+r) div 2;
find(l,mid);
find(mid+1,r);
end;
begin
init;
find(1,n);
writeln(rd:0:3);
end.
point=record
x,y:real;
end;
var
n:longint;
rd:real;
city,r:array[0..100000]of point;
procedure swap(var a,b:real);
var
t:real;
begin
t:=a;a:=b;b:=t;
end;
procedure qsort(l,r:longint);
var
i,j:longint;m:point;
begin
i:=l;j:=r;
m:=city[random(j-i)+i];
repeat
while (city[i].x<m.x)or((city[i].x=m.x)and(city[i].y<m.y)) do inc(i);
while (city[j].x>m.x)or((city[j].x=m.x)and(city[j].y>m.y)) do dec(j);
if i<=j then
begin
swap(city[i].x,city[j].x);
swap(city[i].y,city[j].y);
inc(i);dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end;
function dis(a,b:point):real;
begin
dis:=sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
end;
function min(a,b:real):real;
begin
if a<b then exit(a) else exit(b);
end;
procedure init;
var
i,j:longint;
begin
readln(n);
for i:=1 to n do
with city[i] do
readln(x,y);
qsort(1,n);
rd:=1e10;
for i:=2 to n do rd:=min(rd,dis(city[i-1],city[i]));
end;
procedure work(l,r:longint);
var
i,j,m:longint;d:real;
begin
m:=(l+r) shr 1;
i:=m;
while (l<=i)and(city[m].x-city[i].x<rd) do
begin
j:=m+1;
while (j<=r) and( city[j].x-city[m].x<rd) do
begin
rd:=min(rd,dis(city[i],city[j]));
inc(j);
end;
dec(i);
end;
end;
procedure find(l,r:longint);
var
i,j,t,k,h,mid:longint;d:real;
begin
if l=r then exit;
if l+1=r then
begin
rd:=min(rd,dis(city[l],city[r]));
end;
work(l,r);
mid:=(l+r) div 2;
find(l,mid);
find(mid+1,r);
end;
begin
init;
find(1,n);
writeln(rd:0:3);
end.