BZOJ 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
 

  这一次居然自己想出来了一道还算比较难的题,心里好开心O(∩_∩)O~~

  这道题用到了最小生成树的几个性质。第一,最小生成树每种边权的边数量一定。第二(由第一点可得),当一个图有多个最小生成树时,只可能由一条边替换掉一条等边权的边来得到一颗新的最小生成树。所以,注意到题目中的一个条件:

  具有相同权值的边不会超过10条。

  所以我们就非常地开心。因为这样就可以做了。我们把边按权值排序,然后对于每一块权值相同的边搜索哪些边要选,再统计一下方案数就可以AC辣!

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
 7 #define maxn 5010
 8 #define INF (1LL<<50)
 9 #define mod 31011
10 
11 using namespace std;
12 typedef long long llg;
13 
14 struct data{
15     int u,v,x;
16     bool operator < (const data &h)const{return x<h.x;}
17 }s[maxn];
18 struct dat1{
19     int l,r,x;
20     dat1(int a=0,int b=0,int c=0):l(a),r(b),x(c){};
21 }ss[maxn];
22 int n,m,fa[maxn],ls,la[maxn],w[maxn];
23 llg ans=INF,a1,now,aa=1;
24 bool ww[maxn];
25 
26 int getint(){
27     int w=0,q=0;
28     char c=getchar();
29     while((c<'0'||c>'9')&&c!='-') c=getchar();
30     if(c=='-') q=1,c=getchar();
31     while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
32     return q?-w:w;
33 }
34 
35 int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
36 
37 inline void work(){
38     now=0;int k=0;
39     for(int i=1;i<=n;i++) fa[i]=i;
40     for(int i=1,u,v;i<=m;i++)
41         if(ww[i]){
42             u=s[i].u;v=s[i].v;
43             if(find(u)!=find(v)){
44                 now+=s[i].x; k++;
45                 fa[find(u)]=find(v);
46             }
47     }
48     if(k!=n-1) return;
49     if(now<ans) ans=now,a1=1;
50     else if(now==ans) a1++;
51 }
52 
53 void dfs(int res,int now,int dd){
54     if(now==dd+1){
55         work();return;
56     }
57     if(res){
58         ww[now]=1;
59         dfs(res-1,now+1,dd);
60     }
61     if(dd-now+1>res){
62         ww[now]=0;
63         dfs(res,now+1,dd);
64     }
65 }
66 
67 int main(){
68     n=getint();m=getint();
69     for(int i=1;i<=m;i++){
70         s[i].u=getint();s[i].v=getint();
71         s[i].x=getint();
72     }
73     sort(s+1,s+m+1);
74     for(int i=1;i<=n;i++) fa[i]=i;
75     for(int i=1,u,v;i<=m;i++){
76         w[i]=w[i-1]; ww[i]=1;
77         la[i]=i; u=s[i].u;v=s[i].v;
78         if(s[i-1].x==s[i].x) la[i]=la[i-1];
79         if(find(u)!=find(v)){
80             now+=s[i].x; w[i]++;
81             fa[find(u)]=find(v);
82         }
83         if(la[i]!=i && s[i+1].x!=s[i].x)
84             ss[++ls]=dat1(la[i],i,w[i]-w[la[i]-1]);
85     }
86     for(int i=1;i<=ls;i++){
87         ans=INF;
88         dfs(ss[i].x,ss[i].l,ss[i].r);
89         for(int j=ss[i].l;j<=ss[i].r;j++) ww[j]=1;
90         aa*=a1; aa%=mod;
91     }
92     ans%=mod; aa%=mod;
93     printf("%lld",aa);
94     return 0;
95 }
posted @ 2016-06-11 15:38  lcf2000  阅读(452)  评论(0编辑  收藏  举报