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

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
 
 
首先要知道一个定理,就是在最小生成树中,边权相等的边的数目是固定的。。。
我觉得就是u到v如果存在两条最短路径,如果边权不等的话,那么一定能找到一条更短的路径。。。
然后就可以做了,只要做一次kruskal,找到每个边权出现过多少次
然后对每个边权dfs即可。。。
然后答案用乘法原理。。。
 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<algorithm>
 7 #include<string>
 8 #include<map>
 9 #include<queue>
10 #include<vector>
11 #include<set>
12 #define inf 1000000000
13 #define maxn 10000+5
14 #define maxm 10000+5
15 #define eps 1e-10
16 #define ll long long
17 #define for0(i,n) for(int i=0;i<=(n);i++)
18 #define for1(i,n) for(int i=1;i<=(n);i++)
19 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
20 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
21 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go)
22 using namespace std;
23 int fa[maxn],n,m,sum,cnt,tot,ans=1;
24 struct edge{
25     int u,v,w;
26 }e[maxm];
27 struct data{
28     int l,r,v;
29 }a[maxn];
30 bool cmp(edge a,edge b){
31     return a.w<b.w;
32 }
33 int find(int x){
34     if(fa[x]!=x)return find(fa[x]);
35     else return x;
36 }
37 void dfs(int x,int now,int k){
38     if(now==a[x].r+1){
39         if(k==a[x].v)sum++;
40         return;
41     }
42     int fau=find(e[now].u),fav=find(e[now].v);
43     if(fau!=fav){
44         fa[fav]=fau;
45         dfs(x,now+1,k+1);
46         fa[fav]=fav;fa[fau]=fau;
47     }
48     dfs(x,now+1,k);
49 }
50 int read(){
51     int x=0,f=1;char ch=getchar();
52     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
53     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
54     return x*f;
55 }
56 int main(){
57     //freopen("input.txt","r",stdin);
58     //freopen("output.txt","w",stdout);
59     n=read();m=read();
60     for1(i,n)fa[i]=i;
61     for1(i,m){
62         e[i].u=read();e[i].v=read();e[i].w=read();
63     }
64     sort(1+e,e+m+1,cmp);
65     for1(i,m){
66         if(e[i].w!=e[i-1].w){a[++cnt].l=i;a[cnt-1].r=i-1;}
67         int fau=find(e[i].u),fav=find(e[i].v);
68         if(fau!=fav){
69             fa[fav]=fau;a[cnt].v++;tot++;
70         }
71     }
72     for1(i,n)fa[i]=i;
73     a[cnt].r=m;
74     if(tot!=n-1){printf("0");return 0;}
75     for1(i,cnt){
76         sum=0;
77         dfs(i,a[i].l,0);
78         ans=(ans*sum)%31011;
79         for(int j=a[i].l;j<=a[i].r;j++){
80             int fau=find(e[j].u),fav=find(e[j].v);
81             if(fau!=fav)fa[fav]=fau;
82         }
83     }
84     printf("%d",ans%31011);
85     return 0;
86 }
View Code

 

posted @ 2016-05-16 16:44  HTWX  阅读(107)  评论(0编辑  收藏  举报