用树实现并查集(包括路径压缩和启发式合并)

二、犯罪团伙
group.pas/c/cpp/group.in/group.out
【问题描述:】
警察抓到了n个罪犯,警察根据经验知道他们属于不同的犯罪团伙,却不能判断有多少个团伙,但通过警察的审讯,知道其中的一些罪犯之间相互认识,已知同一犯罪团伙的成员之间直接或间接认识。有可能一个犯罪团伙只有一个人。请你根据已知罪犯之间的关系,确定犯罪团伙的数量。已知罪犯的编号从1至n。
【输入】:
第一行:n(<=10000,罪犯数量),
第二行:m(<100000,关系数量)
以下若干行:每行两个数:I 和j,中间一个空格隔开,表示罪犯i和罪犯j相互认识。
【输出】
一个整数,犯罪团伙的数量。
【样例输入】
11
8
1 2
4 5
3 4
1 3
5 6
7 10
5 10
8 9
【样例输出】
3
说明:共三个集团。

 

1.floodfill 慢

2.way[x,y]一个关系两个点 太大

3.并查集

find(x)

if f[x]=0 exit(x)

find=find(f[x])

f[x]=find{路径压缩,某的老大就是最大的老大}

对于 x,y bossx=find(x) bossy=find(y)

= 无视

<> f[bossx]=bossy{并集}

 

 

 

 

 

 

 

在网上又看了一个启发式合兵,建一个rank数组初始为0,相等则将作最大老大的的结点的rank+1,不相等就把rank大的大老大作最大老大,详见题。。。

自己做的:

program group;

Var
i,j,k,n,m,c:integer;
f:array[0..10000] of integer;
r:array[0..10000] of integer;
function find(a:integer):integer;

begin
   if f[a]=a then
    find:=a else begin
    find:=find(f[a]);
    f[a]:=find;
   end;
end;

procedure un(x,y:integer);

var fx,fy:integer;

begin
   fx:=find(x);fy:=find(y);
if fx<>fy then
begin
   if r[fx]<r[fy] then
    f[fx]:=fy
   else
   begin
    f[fy]:=fx;
    if r[fx]=r[fy] then
     inc(r[fx]);
   end;
end;
end;

begin
assign(input,'group.in');
assign(output,'group.out');
reset(input);
rewrite(output);
readln(n);
readln(m);
fillchar(r,sizeof(r),0);
for k:=1 to n do
   f[k]:=k;
for k:=1 to m do begin
   readln(i,j);
   un(i,j);
end;
for k:=1 to n do
   if f[k]=k then
    inc(c);
writeln(c);
close(input);
close(output);
end.

0
0
(请您对文章做出评价)
posted @ 2010-03-29 09:43  jesonpeng  阅读(342)  评论(0编辑  收藏  举报