最小生成树——[HAOI2006]聪明的猴子

题目:[HAOI2006]聪明的猴子

描述:

【题目描述】



在一个热带雨林中生存着一群猴子,它们以树上的果子为生。昨天下了一场大雨,现在雨过天晴,但整个雨林的地表还是被大水淹没着,

猴子不会游泳,但跳跃能力比较强,它们仍然可以在露出水面的部分植物的树冠上来回穿梭,以找到喜欢吃的果实。

   现在,在这个地区露出水面的有N棵树,假设每棵树本身的直径都很小,可以忽略不计。我们在这块区域上建立直角坐标系,则每一棵树的位置由其所对应的坐标表示(任意两棵树的坐标都不相同)。

   在这个地区住着的猴子有M个,下雨时,它们都躲到了茂密高大的树冠中,没有被大水冲走。由于各个猴子的年龄不同、身体素质不同,它们跳跃的能力不同。有的猴子跳跃的距离比较远(当然也可以跳到较近的树上),而有些猴子跳跃的距离就比较近。这些猴子非常聪明,它们通过目测就可以准确地判断出自己能否跳到对面的树上。

   任务:现已知猴子的数量及每一个猴子的最大跳跃的距离,还知道露出水面的每一棵树的坐标,你的任务是统计有多少猴子可以在这个地区露出水面的所有树冠上觅食。


【输入格式】


第一行一个整数,表示猴子的个数 M(2<=M<=500)

第二行为M个整数,依次表示猴子的最大跳跃距离(每个整数值在1---1000之间)

第三行为一个整数,表示树的总棵树N(2<=N<=1000)

第四行至第N+3行为N棵树的坐标(横纵坐标均为整数,范围为:-1000--1000)


【输出格式】

输出只有一行,包括一个整数,表示可以有这个地区的所有树冠上觅食的猴子数。

【样例输入】

4

1 2 3 4

6

0 0

1 0

1 2

-1 -1

-2 0

2 2

【样例输出】

3

【提示】


对于40%的数据,保证有2<=N<=100,1<=M<=100

对于100%的数据,保证有2<=N<=1000,1<=M<=500

  题目很果,明显的最小生成树,按照坐标计算距离,然后建树即可。记得数组不能开太小,还有就是因为忘了改变父亲节点导致一直A不掉,郁闷了半天,所以存个模版很重要啊!

AC代码:

{

program zht;
var
i,j,m,n,ans,s,hh:longint;
z:array[0..2000] of real;
c,c2:array[0..500000] of real;
a,b,a2,b2:array[0..500000] of longint;
t,bh,f,x,y:array[0..1000] of longint;
procedure gb(low,high:longint);
var
q,w,e,mid,k:longint;
begin
if low=high then exit;
mid:=0;

mid:=(low+high) div 2;
gb(low,mid);
gb(mid+1,high);
q:=0;
w:=0;
e:=0;
q:=low;
w:=mid+1;
e:=low;

while (q<=mid) and (w<=high) do
if c[q]<c[w] then
 begin
 a2[e]:=a[q];
 b2[e]:=b[q];
 c2[e]:=c[q];
 inc(e);
 inc(q);
 end else
  begin
  a2[e]:=a[w];
  b2[e]:=b[w];
  c2[e]:=c[w];
  inc(e);
  inc(w);
  end;

if q<=mid then
 while q<=mid do
 begin
 a2[e]:=a[q];
 b2[e]:=b[q];
 c2[e]:=c[q];
 inc(e);
 inc(q);
 end else
 while w<=high do
 begin
 a2[e]:=a[w];
 b2[e]:=b[w];
 c2[e]:=c[w];
 inc(e);
 inc(w);
end;

for k:=low to high do
begin
a[k]:=a2[k];
b[k]:=b2[k];
c[k]:=c2[k];
end;
end;           // 归并不解释

procedure maketree;   // 建树
var
k,q,w,ss,g:longint;
begin
k:=0;
q:=0;
w:=0;
ss:=0;


while ss<n-1 do
begin
inc(k);
q:=a[k];

fillchar(bh,sizeof(bh),0);

while q<>f[q] do
begin
inc(bh[0]);
bh[bh[0]]:=q;
q:=f[q];
end;

g:=0;

for g:=1 to bh[0] do
f[bh[g]]:=q;        

fillchar(bh,sizeof(bh),0);

w:=b[k];

while w<>f[w] do
begin
inc(bh[0]);
bh[bh[0]]:=w;
w:=f[w];
end;

g:=0;

for g:=1 to bh[0] do
f[bh[g]]:=w;             // 因为COGS的编译器有问题,导致我的并查集只能这么写了~~~有点麻烦,路径压缩和查找就是上面的几段

if q=w then continue;
f[q]:=w;

inc(ss);
z[ss]:=c[k];


end;

end;

begin
assign(input,'monkey.in');
assign(output,'monkey.out');
reset(input);
rewrite(output);

readln(m);
for i:=1 to m do
read(t[i]);

readln(n);

for i:=1 to n do
readln(x[i],y[i]);


for i:=1 to n-1 do
 for j:=i+1 to n do
  begin
  inc(s);
  a[s]:=i;
  b[s]:=j;
  c[s]:=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
 end;                  // 预处理距离


gb(1,s); // 排序
for i:=1 to n do
 f[i]:=i;
maketree;        // 建树


for i:=1 to m do
 begin
 hh:=0;
 for j:=1 to n-1 do
  if z[j]>t[i] then begin hh:=1; break; end;
 if hh=0 then inc(ans);
 end;
writeln(ans);            // 计算答案


close(input);
close(output);
end.
}

<Marvolo原创,严禁转载>
原文地址:https://www.cnblogs.com/zhtjtcz/p/5035731.html