[JSOI2008]最小生成树计数
1016: [JSOI2008]最小生成树计数
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 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
1 2 1
1 3 1
1 4 1
2 3 2
2 4 1
3 4 1
Sample Output
8
Solution 最小生成树,由于相同权值的边不会很多,每次枚举相同的边中有哪些要选择即可,但要保证连通性不变。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
I come, I see, I conquer!