[JSOI2008]最小生成树计数

1016: [JSOI2008]最小生成树计数

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 1577  Solved: 601
[Submit][Status][Discuss]

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


Sample Output

8
 
Solution 最小生成树,由于相同权值的边不会很多,每次枚举相同的边中有哪些要选择即可,但要保证连通性不变。
View Code
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define maxn 1005
 5 #define mod 31011
 6 using namespace std;
 7 struct E {int from, to, tab;}edge[maxn];
 8 int n, m, sz, tot;
 9 int sum[maxn], st[maxn], a[maxn], a2[maxn], vis[maxn], temp, ans = 1;
10 bool cmp(E a, E b) {return a.tab < b.tab;}
11 int fa(int x)
12 {
13     if (a[x] == x) return x;
14     a[x] = fa(a[x]);
15     return a[x];
16 }
17 int fa2(int x) {if (a2[x] == x) return x; else return fa2(a2[x]);}
18 void Un(int x, int y)
19 {
20     int xx = fa(x), yy = fa(y);
21     if (xx != yy) a[xx] = yy;
22 }
23 void dfs(int st, int ed, int sum)
24 {
25     if (sum == 0) {++temp; return;}
26     if (st > ed) return;
27     int fx = fa2(edge[st].from), fy = fa2(edge[st].to);
28     if (vis[edge[st].from] && vis[edge[st].to] && fx != fy)
29     {
30         a2[fx] = fy;
31         dfs(st + 1, ed, sum - 1);
32         a2[fx] = fx;
33     }
34     dfs(st + 1, ed, sum);
35 }
36 void work(int x)
37 {
38     temp = 0;
39     dfs(st[x], st[x + 1] - 1, sum[x]);
40     ans = (ans * temp) % mod;
41 }
42 
43 bool kruskal()
44 {
45     int i, j;
46     sort(edge + 1, edge + m + 1, cmp);
47     for (int i = 1; i <= n; i++) a[i] = a2[i] = i;
48     tot = sz = 0;
49     memset(vis, 0, sizeof(vis));
50     for (i = 1; i <= m; i++)
51     {
52         if (i == 1 || edge[i].tab != edge[i - 1].tab)
53         {
54             st[++tot] = i, sum[tot] = 0;
55             if (i != 1) work(tot - 1);
56             for (j = 1; j <= n; ++j) a2[j] = a[j];
57         }
58         if (fa(edge[i].from) != fa(edge[i].to))
59         {
60             ++sz;
61             Un(edge[i].from, edge[i].to);
62             vis[edge[i].from] = vis[edge[i].to] = 1;
63             ++sum[tot];
64         }
65         if (sz == n - 1) break;
66     }
67     for (j = i + 1; j <= m + 1; ++j)
68         if (edge[j].tab != edge[j - 1].tab) {st[tot + 1] = j; break;}
69     work(tot);
70     if (sz == n - 1) return 1; return 0;
71 }
72 
73 int main()
74 {
75     scanf("%d%d", &n, &m);
76     for (int i = 1; i <= m; i++)
77         scanf("%d %d %d", &edge[i].from, &edge[i].to, &edge[i].tab);
78     if (kruskal()) printf("%d\n", ans); else printf("0\n");
79     return 0;
80 }

 

posted @ 2013-01-20 23:30  Joker0429  阅读(204)  评论(0编辑  收藏  举报