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

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

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,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

Sample Output

8

 

是一道对 kruskal 原理的考察

考虑kruskal 算法的实现过程,我们先将边权排序, 然后从小到大加边

可以发现,所有的最小生成树,每种权值的边的数量是一定了

每次进行完一组相同权值的边的操作时,图的连通性是相同的

ps: 假设在加入权值为 k 的边之前, 图的连通性相同, 每当我们通过存在一条权值为k的边时,对应的点必然会被加入到对应的集合中,所以连通性依然相同

相同权值边数量小于10, 我们可以得到之前的状态,然后DFS枚举, 最后用乘法原理得到答案

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <algorithm>
  4 #include <cstring>
  5 #define LL long long 
  6 using namespace std;
  7 
  8 const int MAXN = 100 + 10, MAXM = 1e3 + 10;
  9 int cnt = 0;
 10 int tot = 0;
 11 int n, m;
 12 LL sum = 0;
 13 LL ans = 1;
 14 LL mod = 31011;
 15 int last = 1;
 16 int T = 0;
 17 int f[2 * MAXN];
 18 int flag[2 * MAXN];
 19 int exs[2 * MAXN];
 20 int father[2 * MAXN];
 21 int use[4 * MAXM];
 22 
 23 
 24 struct wa {
 25     int l, r;
 26     int num;
 27 } wait[4 * MAXM];
 28 struct edge {
 29     int u, v;
 30     int w;
 31 } e[MAXM * 4];
 32 
 33 void init()
 34 {
 35     for(int i = 1; i <= n; i++) {
 36         father[i] = i;
 37     }
 38 }
 39 
 40 int find(int x)
 41 {
 42     if(father[x] != x) {
 43         return find(father[x]);
 44     }
 45     return x;
 46 }
 47 
 48 inline LL read()
 49 {
 50     LL x = 0, w = 1; char ch = 0;
 51     while(ch < '0' || ch > '9') {
 52         if(ch == '-') {
 53             w = -1;
 54         }
 55         ch = getchar();
 56     }
 57     while(ch >= '0' && ch <= '9') {
 58         x = x * 10 + ch - '0';
 59         ch = getchar();
 60     }
 61     return x * w;
 62 }
 63 
 64 bool cmp(edge a, edge b)
 65 {
 66     return a.w < b.w;
 67 }
 68 
 69 /*bool judge(int last, int lim)
 70 {
 71     for(int i = 1; i <= tot; i++) {
 72         f[wait[i]] = wait[i];
 73     }
 74     for(int i = last; i <= lim; i++) {
 75         if(use[i]) {
 76             int x = find2(e[i].u), y = find2(e[i].v);
 77             if(x == y) {
 78                 return false;
 79             } else {
 80                 f[y] = x;
 81             }
 82         }
 83     }
 84     return true;
 85 }*/
 86 
 87 void cal(int k, int lim, int num, int T)
 88 {
 89     if(k == lim + 1) {
 90     //    cout<<num<<endl;
 91         if(num == T) {
 92             sum++;
 93         }
 94         return;
 95     }
 96     cal(k + 1, lim, num, T);
 97     int x = find(e[k].u), y = find(e[k].v);
 98     if(x != y) {
 99         father[y] = x;
100         cal(k + 1, lim, num + 1, T);
101         father[x] = x, father[y] = y;
102     }
103 }
104 int main()
105 {
106     //freopen("award9.in", "r", stdin);
107     //freopen("t.out", "w", stdout);
108     n = read(), m = read();
109     init();
110     for(int i = 1; i <= m; i++) {
111         e[i].u = read(), e[i].v = read(), e[i].w = read();
112     }
113     sort(e + 1,  e + m + 1, cmp);
114     cnt = 0;
115     for(int i = 1; i <= m; i++) {
116         int x = find(e[i].u), y = find(e[i].v);
117         if(x != y) {
118             T++;
119             father[x] = y;
120             sum++;
121         }
122         if(e[i].w != e[i + 1].w) {
123             wait[++cnt].l = last;
124             wait[cnt].r = i;
125             wait[cnt].num = T;
126             T = 0;
127             last = i + 1;
128         }
129     }
130     if(sum < n - 1) {
131         printf("0\n");
132         return 0;
133     }
134     init();
135     for(int i = 1; i <= cnt; i++) {
136         sum = 0;
137         cal(wait[i].l, wait[i].r, 0, wait[i].num);
138     //    cout<<wait[i].l<<" "<<wait[i].r<<" "<<wait[i].num<<endl;
139     //    cout<<sum<<endl<<endl;
140         for(int j = wait[i].l; j <= wait[i].r; j++) {
141             int x = find(e[j].u), y = find(e[j].v);
142             if(x != y) {
143                 father[y] = x;
144             }
145         }    
146         ans = ans * sum % mod;
147     }
148     printf("%lld\n", ans);
149 }
View Code

 

posted @ 2018-02-10 10:02  大财主  阅读(...)  评论(... 编辑 收藏