[题目描述]
给你n个点,求最近点对和最远点对,n<=100000
[题解]
计算几何裸题,由于本沙茶不会最近点对的二分算法,加上ws的出题人卡住了随机算法,于是苦B的打了一个2-d树交上去....
用2-d树做最近点对的应该就只有我这个若b了吧好心酸TAT,幸好没卡2-d树,不然白打了140行的代码啊...
代码量骤增(虽然我不知道二分的代码量怎么样,但这个140行的程序代码量算是很大的了)
这个代码最沙茶的地方在于:我用两个向量相乘来表示所选维度的值!!!!等我发现可以直接用下标搞的时候已经来不及改了TAT.另外我在划分的地方纠结了好久...
交了6次才A,我是有多弱啊......
Code:
program k_d_tree;{$INLINE ON}
type
int=longint;
real=extended;
point=record x,y:real;end;
line=record a,b,c:real;end;
const e=1e-9;maxn=200000;
operator -(a,b:point)c:Point;inline;
begin c.x:=a.x-b.x;c.y:=a.y-b.y;end;
operator *(a,b:point)c:real;inline;
begin c:=a.x*b.y-a.y*b.x;end;
operator /(a,b:point)c:real;inline;
begin c:=sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));end;
operator =(a:point;b:line)c:boolean;inline;
begin c:=b.a*a.x+b.b*a.y>b.c-e;end;
operator **(a:point;b:line)c:real;inline;
begin c:=b.a*a.x+b.b*a.y;end;
var
i,j,k,m,n,pos:int;
l:array[1..maxn*2]of line;
a:array[0..maxn+1]of point;
ll,rr,p:array[0..maxn*2]of int;
x,t,y,s:point;li:line;
ans,z:real;
procedure sort(ll,r,k:int);
var i,j:int;
begin
i:=ll;j:=r;
x:=a[(ll+r)>>1];
repeat
while a[i]**li<x**li do inc(i);
while a[j]**li>x**li do dec(j);
if i<=j then begin
t:=a[i];a[i]:=a[j];a[j]:=t;
inc(i);dec(j);
end;
until i>j;
if(i<r)and(a[k]**li>=x**li)then sort(i,r,k);
if(j>ll)and(a[k]**li<=x**li)then sort(ll,j,k);
end;
procedure build(rt,lb,rb:int);
var mid:int;
begin
if random(2)=1 then l[rt].a:=1
else l[rt].b:=1;
mid:=(lb+rb)>>1;li:=l[rt];
ll[rt]:=lb;rr[rt]:=rb;
sort(lb,rb,mid);
l[rt].c:=a[mid]**li;
if mid>lb then build(rt<<1,lb,mid-1);
if mid<rb then build(rt<<1+1,mid+1,rb);
end;
procedure ask(rt:int);
var mid:int;
begin
mid:=(ll[rt]+rr[rt])>>1;
if(mid<>pos)and(x/a[mid]<ans)then ans:=x/a[mid];
if abs(x**l[rt]-l[rt].c)>ans+e then begin
if(mid>ll[rt])and(x**l[rt]<a[mid]**l[rt])then ask(rt<<1)
else if mid<rr[rt] then ask(rt<<1+1);
end else begin
if mid>ll[rt] then ask(rt<<1);
if mid<rr[rt] then ask(rt<<1+1);
end;
end;
procedure sort1(l,r:int);
var i,j:int;
begin
z:=a[(l+r)>>1].x;
i:=l;j:=r;
repeat
while a[i].x<z do inc(i);
while a[j].x>z do dec(j);
if i<=j then begin
t:=a[i];a[i]:=a[j];a[j]:=t;
inc(i);dec(j);
end;
until i>J;
if i<r then sort1(i,r);
if j>l then sort1(l,j);
end;
procedure hull;
begin
p[0]:=1;p[1]:=2;m:=1;
for i:=3 to n do begin
while(m>0)and((a[p[m-1]]-a[p[m]])*(a[p[m]]-a[i])>0)do dec(m);
inc(m);p[m]:=i;
end;
for i:=n-1 downto 1 do begin
while((a[p[m-1]]-a[p[m]])*(a[p[m]]-a[i])>0)do dec(m);
inc(m);p[m]:=i;
end;
end;
procedure up(var x:int);
begin x:=(x+1)mod(m+1);end;
procedure down(var x:int);
begin x:=x-1;if x=-1 then x:=m;end;
procedure main;
begin
j:=1;ans:=0;
for i:=1 to m do begin
s:=a[p[i]]-a[p[i-1]];
z:=s*(a[p[i]]-a[p[j]]);up(j);
while(s*(a[p[i]]-a[p[j]])-z>-e)do begin
z:=s*(a[p[i]]-a[p[j]]);up(j);
end;
down(j);
if(a[p[i]]/a[p[j]]>ans)then ans:=a[p[i]]/a[p[j]];
if(a[p[i]]/a[p[i-1]]>ans)then ans:=a[p[i]]/a[p[i-1]];
end;
write(ans:0:2);
end;
begin
assign(input,'data.txt');reset(input);
assign(output,'k_d.out');rewrite(output);
read(n);a[0].x:=1e30;a[0].y:=1e30;a[n+1]:=a[0];
for i:=1 to n do read(a[i].x,a[i].y);
fillchar(l,sizeof(l),0);
build(1,1,n);
ans:=1e30;
for i:=1 to n do begin
x:=a[i];pos:=i;ask(1);
end;
write(ans:0:2,' ');
sort1(1,n);
hull;
main;
close(input);close(output);
end.
-2012-12-27
好吧,我承认我nc了.
题目的数据并没有卡住随机算法,是我忘记加abs导致跳不了了...
各位神牛尽情地D我吧....
另外求能卡住最近点对的随机算法的数据
有的请私信Orz
有想法的也可以跟我聊一下