Time Limit: 1 Sec
Memory Limit: 162 MB
Description
现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。由于不同的最小生成树可能很多,所以你只需要输出方案数对31011的模就可以了。
Input
第一行包含两个数,n和m,其中1<=n<=100; 1<=m<=1000; 表示该无向图的节点数和边数。每个节点用1~n的整数编号。接下来的m行,每行包含两个整数:a, b, c,表示节点a, b之间的边的权值为c,其中1<=c<=1,000,000,000。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过10条。
Output
输出不同的最小生成树有多少个。你只需要输出数量对31011的模就可以了。
Sample Input
4 6
1 2 1
1 3 1
1 4 1
2 3 2
2 4 1
3 4 1
1 2 1
1 3 1
1 4 1
2 3 2
2 4 1
3 4 1
Sample Output
8
先做一次kruskal,求出每一种权值为Ci的边所用的条数(记作Ni)。根据定理,对于每一棵最小生成树,其中权值为Ci的边都必须用Ni条。用dfs枚举所用边,用并查集判断是否可行即可。最后用乘法原理求出答案。
AC CODE
program
hy_1016;
const
mo=
31011
;
var
x,y,c:
array
[
1..1000
]
of
longint
;
fa,fa2,use:
array
[
1..100
]
of
longint
;
p:
array
[
1..1000
]
of
boolean
;
way,num,s,t,used,n,m:
longint
;
//============================================================================
procedure
qsort(l,r:
longint
);
var
k,i,j,t:
longint
;
begin
k:=c[(l+r)
shr
1
]; i:=l; j:=r;
repeat
while
c[i]<k
do
inc(i);
while
c[j]>k
do
dec(j);
if
i<=j
then
begin
t:=c[i]; c[i]:=c[j]; c[j]:=t;
t:=x[i]; x[i]:=x[j]; x[j]:=t;
t:=y[i]; y[i]:=y[j]; y[j]:=t;
inc(i); dec(j);
end
;
until
i>j;
if
j>l
then
qsort(l,j);
if
i<r
then
qsort(i,r);
end
;
//============================================================================
procedure
init;
var
i:
longint
;
begin
readln(n,m);
for
i:=
1
to
m
do
readln(x[i],y[i],c[i]);
for
i:=
1
to
n
do
fa[i]:=i;
for
i:=
1
to
m
do
p[i]:=
false
;
qsort(
1
,m);
end
;
//============================================================================
function
getfa(x:
longint
):
longint
;
begin
if
fa[x]<>x
then
fa[x]:=getfa(fa[x]);
exit(fa[x]);
end
;
//============================================================================
function
getfa2(x:
longint
):
longint
;
begin
if
fa2[x]<>x
then
fa2[x]:=getfa2(fa2[x]);
exit(fa2[x]);
end
;
//============================================================================
procedure
kruskal;
var
all,i,fx,fy:
longint
;
begin
all:=
0
;
for
i:=
1
to
m
do
begin
fx:=getfa(x[i]);
fy:=getfa(y[i]);
if
fx=fy
then
continue
else
fa[fx]:=fy;
inc(all); p[i]:=
true
;
if
all=n-
1
then
break;
end
;
if
all<n-
1
then
begin
writeln
(
'0'
); halt;
end
;
end
;
//============================================================================
procedure
judge;
var
i,fx,fy:
longint
;
begin
for
i:=
1
to
n
do
fa2[i]:=fa[i];
for
i:=s
to
t
do
if
use[i-s+
1
]=
1
then
begin
fx:=getfa2(x[i]);
fy:=getfa2(y[i]);
fa2[fx]:=fy;
if
fx=fy
then
exit;
end
; inc(way);
end
;
//============================================================================
procedure
dfs(x:
longint
);
begin
if
x=t-s+
2
then
begin
judge; exit;
end
;
if
used+t-s+
1
-x+
1
=num
then
begin
use[x]:=
1
; inc(used);
dfs(x+
1
); dec(used);
end
else
begin
use[x]:=
0
; dfs(x+
1
);
use[x]:=
1
;
inc(used); dfs(x+
1
); dec(used);
end
;
end
;
//============================================================================
procedure
work;
var
i,fx,fy,ans:
longint
;
begin
s:=
0
; t:=
0
; ans:=
1
;
while
t<m
do
begin
s:=t+
1
; num:=
0
;
for
i:=s
to
m
do
begin
if
p[i]
then
inc(num);
if
c[i]<>c[i+
1
]
then
break;
end
; t:=i;
if
num=
0
then
continue;
for
i:=
1
to
n
do
fa[i]:=i;
for
i:=
1
to
s-
1
do
if
p[i]
then
begin
fx:=getfa(x[i]);
fy:=getfa(y[i]);
fa[fx]:=fy;
end
;
for
i:=t+
1
to
m
do
if
p[i]
then
begin
fx:=getfa(x[i]);
fy:=getfa(y[i]);
fa[fx]:=fy;
end
;
used:=
0
; way:=
0
; dfs(
1
);
ans:=(ans*way)
mod
mo;
end
;
writeln
(ans);
end
;
//============================================================================
begin
init;
kruskal;
work;
end
.