BZOJ 1016 JSOI2008 最小生成树计数

Posted zhangenming

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1016 JSOI2008 最小生成树计数相关的知识,希望对你有一定的参考价值。

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

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 6643  Solved: 2711
[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,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

HINT

Source

根据kruskal算法的基础是贪心,我们可以得出,不同的最小生成树的边权序列是一样的

我们先做出kruskal得出最终的边权序列,然后逐个枚举每个边权有多少种不同的组成方法

最后乘法原理乘起来即可,要注意使用并查集的时候不要带路径压缩,不要的话dfs就回溯不了了,但这样效率会变低

不嫌麻烦的话写两个,我太懒了QAQ

技术分享图片
 1 #include <bits/stdc++.h>
 2 #define ll long long
 3 #define inf 1000000
 4 #define eps 1e-7
 5 #define MOD 31011
 6 using namespace std;
 7 inline int read(){
 8     int x=0;int f=1;char ch=getchar();
 9     while(!isdigit(ch)) {if(ch==-) f=-1;ch=getchar();}
10     while(isdigit(ch)) {x=x*10+ch-0;ch=getchar();}
11     return x*f;
12 }
13 const int MAXN=1e6+10;
14 struct node{
15     int x,y,v;
16 }e[MAXN];
17 struct edge{
18     int l,r,v;
19 }a[MAXN];
20 int f[MAXN],cnt,tot,sum;
21 inline int find(int x){
22     return x==f[x]?x:find(f[x]);
23 }
24 inline bool mycmp(node n,node m){
25     return n.v<m.v;
26 }
27 inline void dfs(int st,int now,int k){
28     if(now==a[st].r+1){
29         if(k==a[st].v) sum++;
30         return;
31     }
32     int fx=find(e[now].x);int fy=find(e[now].y);
33     if(fx!=fy){
34         f[fx]=fy;
35         dfs(st,now+1,k+1);
36         f[fx]=fx;f[fy]=fy;
37     }
38     dfs(st,now+1,k);
39 }
40 int main(){
41     int n=read();int m=read();
42     for(int i=1;i<=m;i++){
43         e[i].x=read();e[i].y=read();e[i].v=read();
44     }
45     for(int i=1;i<=n;i++) f[i]=i;
46     sort(e+1,e+m+1,mycmp);
47     for(int i=1;i<=m;i++){
48         if(e[i].v!=e[i-1].v){
49             a[++cnt].l=i;a[cnt-1].r=i-1;
50         }
51         int fx=find(e[i].x);int fy=find(e[i].y);
52         if(fx!=fy){
53             a[cnt].v++;f[fx]=fy;tot++;
54         }
55     }
56     a[cnt].r=m;
57     for(int i=1;i<=n;i++) f[i]=i;
58     if(tot!=n-1){
59        cout<<0<<endl;return 0;
60     }
61     int ans=1;
62     for(int i=1;i<=cnt;i++){
63         sum=0;
64         dfs(i,a[i].l,0);
65         ans*=sum;
66         ans%=MOD;
67         for(int j=a[i].l;j<=a[i].r;j++){
68             f[find(e[j].x)]=find(e[j].y);
69         }
70     } 
71     cout<<ans<<endl;
72     return 0;
73 }
View Code

 













以上是关于BZOJ 1016 JSOI2008 最小生成树计数的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ-1016: [JSOI2008]最小生成树计数 (kruscal+搜索)

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

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

BZOJ1016:[JSOI2008]最小生成树计数——题解

BZOJ1016: [JSOI2008]最小生成树计数 深搜+并查集

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