[BZOJ1016] [JSOI2008] 最小生成树计数 (Kruskal)
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,0
00。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过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
HINT
Source
Solution
最小生成树的性质:
- 对于每一个$MST$,每一种边权所使用的边数相同
- 所有$MST$中边权$\leq w$的边组成的图的连通性相同
所以首先我们可以用$Kruskal$算出每一种边权使用的边数
之后暴力枚举某种边权所使用的边
因为最多只有$10$条边,所以时间可以接受,当没有这个限制条件时需要用到$Matrix$-$Tree$定理。对,你知道的,我不会这个
顺便试着写了下冰炸鸡并查集按秩合并,稍微伪证了一下发现是$O(nlogn)$的,不过可以撤回?!好像又解锁了什么姿势
1 #include <bits/stdc++.h> 2 using namespace std; 3 struct edge 4 { 5 int u, v, w, x; 6 inline bool operator< (const edge &rhs) const 7 { 8 return x < rhs.x; 9 } 10 }e[1005]; 11 struct count 12 { 13 int l, r, use; 14 }g[1005]; 15 int n, m, fa[105], siz[105]; 16 17 int getfa(int x) 18 { 19 return fa[x] == x ? x : getfa(fa[x]); 20 } 21 22 void link(int u, int v) 23 { 24 if(siz[u] > siz[v]) fa[v] = u, siz[u] += siz[v]; 25 else fa[u] = v, siz[v] += siz[u]; 26 } 27 28 bool Kruskal() 29 { 30 int cnt = 0, u, v; 31 for(int i = 1; i <= m; ++i) 32 { 33 u = getfa(e[i].u), v = getfa(e[i].v); 34 if(u != v) 35 { 36 link(u, v); 37 ++g[e[i].w].use; 38 if(++cnt == n - 1) return true; 39 } 40 } 41 return false; 42 } 43 44 int DFS(int w, int i, int k) 45 { 46 if(k == g[w].use) return 1; 47 if(i > g[w].r) return 0; 48 int ans = 0, u = getfa(e[i].u), v = getfa(e[i].v); 49 if(u != v) 50 { 51 link(u, v); 52 ans = DFS(w, i + 1, k + 1); 53 fa[u] = u, fa[v] = v; 54 } 55 return ans + DFS(w, i + 1, k); 56 } 57 58 int main() 59 { 60 int u, v, w, ans; 61 cin >> n >> m; 62 for(int i = 1; i <= n; ++i) 63 fa[i] = i, siz[i] = 1; 64 for(int i = 1; i <= m; ++i) 65 { 66 cin >> u >> v >> w; 67 e[i] = (edge){u, v, 0, w}; 68 } 69 sort(e + 1, e + m + 1); 70 w = 0; 71 for(int i = 1; i <= m; ++i) 72 if(e[i].x == e[i - 1].x) e[i].w = w; 73 else 74 { 75 g[w].r = i - 1; 76 e[i].w = ++w; 77 g[w].l = i; 78 } 79 g[w].r = m; 80 ans = Kruskal(); 81 for(int i = 1; i <= n; ++i) 82 fa[i] = i, siz[i] = 1; 83 for(int i = 1; i <= w; ++i) 84 { 85 ans = ans * DFS(i, g[i].l, 0) % 31011; 86 for(int j = g[i].l; j <= g[i].r; ++j) 87 { 88 u = getfa(e[j].u), v = getfa(e[j].v); 89 if(u != v) link(u, v); 90 } 91 } 92 cout << ans << endl; 93 return 0; 94 }