【BZOJ 1016】 1016: [JSOI2008]最小生成树计数 (DFS|矩阵树定理)

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

HINT

Source

【分析】

  不知道结论是不可以做的吧?表示也不会矩阵树定理。。dfs方法也要知道一些证明才能说明其准确性。

  【以后的博客都要留坑了?

  安利两种题解:

  1、我的打法:(不看都不知道为什么这样做是对的)

  https://blog.sengxian.com/solutions/bzoj-1016

  http://www.cnblogs.com/lcf-2000/p/5575412.html

  2、矩阵树(没打这种,还不会)

  http://blog.csdn.net/jarily/article/details/8902509

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 #define Maxn 1100
 8 #define Maxm 10100
 9 #define Mod 31011
10 
11 struct node
12 {
13     int x,y,c;
14 }t[Maxm];
15 
16 bool cmp(node x,node y) {return x.c<y.c;}
17 int a[Maxm],l[Maxm],r[Maxm],fa[Maxn];
18 
19 int ffa(int x)
20 {
21      return x==fa[x]?x:ffa(fa[x]);
22 }
23 
24 int ct;
25 void ffind(int x,int nw,int h)
26 {
27     if(nw==r[x]+1)
28     {
29         if(h==a[x]) ct++;
30         return;
31     }
32     int x1=ffa(t[nw].x),x2=ffa(t[nw].y);
33     if(x1!=x2)
34     {
35         fa[x1]=x2;
36         ffind(x,nw+1,h+1);
37         fa[x1]=x1;
38     }
39     ffind(x,nw+1,h);
40 }
41 
42 int main()
43 {
44     int n,m;
45     scanf("%d%d",&n,&m);
46     for(int i=1;i<=m;i++)
47     {
48         scanf("%d%d%d",&t[i].x,&t[i].y,&t[i].c);
49     }
50     sort(t+1,t+1+m,cmp);
51     int cnt=0,tot=0;
52     for(int i=1;i<=n;i++) fa[i]=i;
53     for(int i=1;i<=m;i++)
54     {
55         if(i==1||t[i].c!=t[i-1].c)
56         {
57             r[cnt]=i-1;l[++cnt]=i;
58             a[cnt]=0;
59         }
60         int x1=ffa(t[i].x),x2=ffa(t[i].y);
61         if(x1!=x2)
62         {
63             fa[x1]=x2;
64             a[cnt]++;
65             tot++;
66         }
67         
68     }r[cnt]=m;
69     if(tot!=n-1) printf("0
");
70     else
71     {
72         for(int i=1;i<=n;i++) fa[i]=i;
73         int ans=1;
74         for(int i=1;i<=cnt;i++)
75         {
76             ct=0;
77             ffind(i,l[i],0);
78             ct%=Mod;
79             ans=ans*ct;ans%=Mod;
80             for(int j=l[i];j<=r[i];j++)
81             {
82                 int x1=ffa(t[j].x),x2=ffa(t[j].y);
83                 if(x1!=x2) fa[x1]=x2;
84             }
85         }
86         printf("%d
",ans);
87     }
88     return 0;
89 }
View Code

2017-02-28 13:58:04

原文地址:https://www.cnblogs.com/Konjakmoyu/p/6478555.html