就是求最小公共祖先
求最小公共祖先有脱机和在线两种算法,<<算法艺术>>中有介绍,这题我用的是脱机最小公共祖先算法,速度快些。
求脱机最小公共祖先算法用到了并查集 ,算法描述如下:
LCA(u)
MAKE-SET(u)
ancestor[FIND-SET(u)] <- u
for each child v of u in T
do LCA(v)
UNION(u,v)
ancestor[FIND-SET(u)] <- u
color[u] <- BLACK
for each node v suck that [u,v] belong P
do if color[v]=BACL
then print "The least common ancestor of" u " and " v "is" ancestor[FIND-SET(v)]
可以证明对于每一对{u,v}belong P,最后一行恰执行一次.
my code :
1
#include
<
iostream
>
2
#include
<
vector
>
3
using
namespace
std;
4
5
#define
BLACK true
6
#define
WHITE false
7
8
const
int
MAXN
=
1000
;
9
10
vector
<
int
>
tree[ MAXN
+
1
];
//
树的结构,所有儿子表示法
11
bool
br[ MAXN
+
1
];
//
标记数组,方便求出树的根
12
bool
color[ MAXN
+
1
];
//
LCA遍历中的标记数组
13
int
ancestor[ MAXN
+
1
];
//
最小公共祖先
14
int
p[ MAXN
+
1
],rank[ MAXN
+
1
];
//
并查集
15
int
total[ MAXN
+
1
];
//
存放结果
16
vector
<
int
>
s[ MAXN
+
1
];
//
集合P
17
18
void
makeset(
int
x ) {
19
p[ x ]
=
x;
20
rank[ x ]
=
0
;
21
}
22
int
findset(
int
x ) {
23
if
( x
!=
p[ x ] )
24
p[ x ]
=
findset( p[ x ] );
25
return
p[ x ];
26
}
27
void
link(
int
x,
int
y ) {
28
if
( rank[ x ]
>
rank[ y ] )
29
p[ y ]
=
p[ x ];
30
else
{
31
p[ x ]
=
p[ y ];
32
if
( rank[ x ]
==
rank[ y ] )
33
rank[ y ]
++
;
34
}
35
}
36
37
void
LCA(
int
u ) {
38
makeset( u );
39
ancestor[ findset( u ) ]
=
u;
40
for
(
int
i
=
0
;i
<
tree[ u ].size( );i
++
) {
41
LCA( tree[ u ][ i ] );
42
link( u,tree[ u ][ i ] );
43
ancestor[ findset( u ) ]
=
u;
44
}
45
color[ u ]
=
BLACK;
46
for
(
int
i
=
0
;i
<
s[ u ].size( );i
++
) {
47
if
( color[ s[ u ][ i ] ]
==
BLACK ) {
48
total[ ancestor[ findset( s[ u ][ i ] ) ] ]
++
;
49
}
50
}
51
}
52
53
int
main( ) {
54
int
n,n1,node,a,root,b;
55
char
c1,c2,c3;
56
while
(cin
>>
n) {
57
memset( br,
true
,
sizeof
br );
58
memset( color,WHITE,
sizeof
color );
59
memset( total,
0
,
sizeof
total );
60
for
(
int
i
=
1
;i
<
MAXN;i
++
) {
61
s[ i ].clear( );
62
tree[ i ].clear( );
63
}
64
65
for
(
int
i
=
0
;i
<
n;i
++
) {
66
cin
>>
node
>>
c1
>>
c2
>>
n1
>>
c3;
67
if
( n1
>
0
) {
68
for
(
int
j
=
0
;j
<
n1;j
++
) {
69
cin
>>
a;
70
tree[ node ].push_back( a );
71
br[ a ]
=
false
;
72
}
73
}
74
}
75
for
(
int
i
=
1
;i
<=
n;i
++
)
76
if
( br[ i ] ) {
77
root
=
i;
78
break
;
79
}
80
81
cin
>>
n1;
82
for
(
int
i
=
0
;i
<
n1;i
++
) {
83
cin
>>
c1
>>
a
>>
c2
>>
b
>>
c3;
84
s[ a ].push_back( b );
85
s[ b ].push_back( a );
86
}
87
88
LCA( root );
89
for
(
int
i
=
1
;i
<=
n;i
++
) {
90
if
( total[ i ]
>
0
)
91
cout
<<
i
<<
"
:
"
<<
total[ i ]
<<
endl;
92
}
93
}
94
return
0
;
95
}
96