[JSOI2008]最小生成树计数

 [JSOI2008]最小生成树计数

时间限制: 1 Sec  内存限制: 162 MB

题目描述

  现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的
最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。由于不同的最小生
成树可能很多,所以你只需要输出方案数对31011的模就可以了。

输入

  第一行包含两个数,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条。

输出

  输出不同的最小生成树有多少个。你只需要输出数量对31011的模就可以了。

样例输入

4 6
1 2 1
1 3 1
1 4 1
2 3 2
2 4 1
3 4 1

样例输出

8

Solution:
    表示并不会Matrix-Tree,直接暴力就好了。
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 using namespace std;
 6 #define mod 31011
 7 #define N 105
 8 #define M 1005
 9 int read() {
10     int s=0,f=1;
11     char ch=getchar();
12     for( ; ch<'0'||ch>'9'; f=(ch=='-')?-1:f,ch=getchar()) ;
13     for( ; ch>='0'&&ch<='9'; s=s*10+(ch^48),ch=getchar()) ;
14     return s*f;
15 }
16 int n,m,Ans=1;
17 struct EDGE {
18     int fr,to,w;
19     friend bool operator < (EDGE a,EDGE b) {return a.w<b.w;}
20 } Edge[M];
21 struct MST {
22     int Fa[N];
23     int find(int x) {return Fa[x]==x?x:Fa[x]=find(Fa[x]);}
24     void init() {for(int i=1; i<=n; ++i) Fa[i]=i;}
25     int Count() {
26         int ans=0;
27         for(int i=1; i<=n; ++i) if(Fa[i]==i) ++ans;
28         return ans;
29     }
30     bool Union(int x,int y) {
31         int fx=find(x),fy=find(y);
32         if(fx!=fy) Fa[fx]=fy;
33         return fx!=fy;
34     }
35 } A,B,C;
36 int main() {
37     //freopen("bzoj_1016.in","r",stdin);
38     //freopen("bzoj_1016.out","w",stdout);
39     n=read(),m=read();
40     if(m<n-1) {puts("0"); return 0;}
41     for(int x,y,z,i=1; i<=m; ++i) Edge[i]=(EDGE){x=read(),y=read(),z=read()};
42     sort(Edge+1,Edge+m+1); A.init(),C.init();
43     for(int begin=1,Q=1,cnt,len; Q<=m; ++Q) {
44         if(Q==m||Edge[Q].w!=Edge[Q+1].w) {
45             for(int i=begin; i<=Q; ++i) C.Union(Edge[i].fr,Edge[i].to);
46             len=Q-begin+1; cnt=0;
47             for(int State=0; State<(1<<len); ++State) {
48                 int now=1;
49                 for(int i=1; i<=n; ++i) B.Fa[i]=A.Fa[i];
50                 for(int i=1; i<=len; ++i) {
51                     if(State&(1<<(i-1))) {
52                         int U=Edge[i+begin-1].fr,V=Edge[i+begin-1].to;
53                         if(!B.Union(U,V)) {now=0; break;}
54                     }
55                 } if(now) if(C.Count()!=B.Count()) now=0;
56                 cnt+=now;
57             } Ans=(Ans*cnt)%mod;
58             for(int i=1; i<=n; ++i) A.Fa[i]=C.Fa[i];
59             begin=Q+1;
60         }
61     } printf("%d",Ans);
62     return 0;
63 }

 

 
posted @ 2017-11-06 15:49  Forever_goodboy  阅读(212)  评论(0编辑  收藏  举报