题目描述
现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。由于不同的最小生成树可能很多,所以你只需要输出方案数对31011的模就可以了。
输入
第一行包含两个数,n和m,其中1<=n<=100; 1<=m<=1000; 表示该无向图的节点数和边数。每个节点用1~n的整数编号。接下来的m行,每行包含两个整数:a, b, c,表示节点a, b之间的边的权值为c,其中1<=c<=1,000,000,000。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过10条。
输出
输出不同的最小生成树有多少个。你只需要输出数量对31011的模就可以了。
样例输入
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
样例输出
8
题解:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mod 31011
using
namespace
std
;
int
n
,
m
,
cnt
,
tot
,
ans
=
1
,
sum
;
int
fa
[
105
]
;
struct
edge
{
int
x
,
y
,
v
;
}
e
[
1005
]
;
struct
data
{
int
l
,
r
,
v
;
}
a
[
1005
]
;
inline
int
read
(
)
{
int
x
=
0
;
char
ch
=
getchar
(
)
;
while
(
ch
<
'0'
||
ch
>
'9'
)
{
ch
=
getchar
(
)
;
}
while
(
ch
>=
'0'
&&
ch
<=
'9'
)
{
x
=
x
*
10
+
ch
-
'0'
;
ch
=
getchar
(
)
;
}
return
x
;
}
bool
cmp
(
edge
a
,
edge
b
)
{
return
a
.
v
<
b
.
v
;
}
int
find
(
int
x
)
{
return
x
==
fa
[
x
]
?
x
:
find
(
fa
[
x
]
)
;
}
void
dfs
(
int
x
,
int
now
,
int
k
)//只要符合条件(k==a[x].v),那这里面出现的点必定联通,即效果是一样的
{
if
(
now
==
a
[
x
]
.
r
+
1
)
{
if
(
k
==
a
[
x
]
.
v
)
sum
++
;
return
;
}
int
p
=
find
(
e
[
now
]
.
x
)
,
q
=
find
(
e
[
now
]
.
y
)
;
if
(
p
!=
q
)
{
fa
[
p
]
=
q
;
dfs
(
x
,
now
+
1
,
k
+
1
)
;
fa
[
p
]
=
p
;
fa
[
q
]
=
q
;
}
dfs
(
x
,
now
+
1
,
k
)
;
}
int
main
(
)
{
n
=
read
(
)
;
m
=
read
(
)
;
for
(
int
i
=
1
;
i
<=
n
;
i
++
)
fa
[
i
]
=
i
;
for
(
int
i
=
1
;
i
<=
m
;
i
++
)
e
[
i
]
.
x
=
read
(
)
,
e
[
i
]
.
y
=
read
(
)
,
e
[
i
]
.
v
=
read
(
)
;
sort
(
e
+
1
,
e
+
m
+
1
,
cmp
)
;
for
(
int
i
=
1
;
i
<=
m
;
i
++
)
{
if
(
e
[
i
]
.
v
!=
e
[
i
-
1
]
.
v
)
{
a
[
++
cnt
]
.
l
=
i
;
a
[
cnt
-
1
]
.
r
=
i
-
1
;
}
int
p
=
find
(
e
[
i
]
.
x
)
,
q
=
find
(
e
[
i
]
.
y
)
;
if
(
p
!=
q
)
{
fa
[
p
]
=
q
;
a
[
cnt
]
.
v
++
;
tot
++
;
}
}
a
[
cnt
]
.
r
=
m
;
if
(
tot
!=
n
-
1
)
{
printf
(
"0"
)
;
return
0
;
}
for
(
int
i
=
1
;
i
<=
n
;
i
++
)
fa
[
i
]
=
i
;
for
(
int
i
=
1
;
i
<=
cnt
;
i
++
)
{
sum
=
0
;
dfs
(
i
,
a
[
i
]
.
l
,
0
)
;
ans
=
(
ans
*
sum
)
%
mod
;
for
(
int
j
=
a
[
i
]
.
l
;
j
<=
a
[
i
]
.
r
;
j
++
)
{
int
p
=
find
(
e
[
j
]
.
x
)
,
q
=
find
(
e
[
j
]
.
y
)
;
if
(
p
!=
q
)
fa
[
p
]
=
q
;
}//会觉得有问题吗??为什么在这里出现的点之后一定联通?想一下,如果不连通的话,是不是要用之后的边来联通?要知道,边已经按权值大小排列好了。
}
printf
(
"%d"
,
ans
)
;
return
0
;
}