bzoj1016: [JSOI2008]最小生成树计数(kruskal+dfs)

Posted CHerish_OI

tags:

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

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

题目:传送门 

题解:

   神题神题%%%

   据说最小生成树有两个神奇的定理:

   1、权值相等的边在不同方案数中边数相等

      就是说如果一种方案中权值为1的边有n条

      那么在另一种方案中权值为1的边也一定有n条

 

   2、如果边权为1的边连接的点是x1,x2,x3

      那么另一种方案中边权为1的边连接的也一定是x1,x2,x3

  

   如果知道了这两条定理那就很好做了啊:

   因为等权边的条数一定,那么我们就可以预处理求出不同边权的边的条数

   题目很人道的保证了边权相同的边不会超过10条,那就可以光明正大的递归得出方案数了啊

   

   接下来就要利用定理2了:

   因为连接的点总是不变的,所以每一次选边是没有影响的,那么递归求出每一种权值边的方案数之后用乘法原理乘起来就ok

 

代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cmath>
 5 #include<algorithm>
 6 #define mod 31011
 7 #define qread(x) x=read()
 8 using namespace std;
 9 inline int read()
10 {
11     int f=1,x=0;char ch;
12     while(ch<0 || ch>9){if(ch==-)f=-1;ch=getchar();}
13     while(ch>=0 && ch<=9){x=x*10+ch-0;ch=getchar();}
14     return f*x;
15 }
16 struct node
17 {
18     int x,y,c,next;
19 }a[1100];int n,m,sum;
20 int fa[110];
21 int findfa(int x)
22 {
23     if(x==fa[x])return x;
24     return findfa(fa[x]);
25 }
26 bool cmp(node n1,node n2)
27 {
28     return n1.c<n2.c;
29 }
30 int d[1100],s[1100];
31 void dfs(int k,int t,int i)//当前选的是第k种边,已经选了t条,当前位置为第i条边 
32 {
33     if(i==s[k]+1)
34     { 
35         if(t==d[k])
36             sum++,sum%=mod;
37         return ;
38     }
39     int fx=findfa(a[i].x),fy=findfa(a[i].y);
40     if(fx!=fy)
41     {
42         fa[fx]=fy;
43         dfs(k,t+1,i+1);
44         fa[fx]=fx;
45     }
46     dfs(k,t,i+1);
47 }
48 int main()
49 {
50     qread(n);qread(m);
51     for(int i=1;i<=m;i++){qread(a[i].x);qread(a[i].y);qread(a[i].c);}
52     sort(a+1,a+m+1,cmp);
53     for(int i=1;i<=n;i++)fa[i]=i;
54     int k=1,t=0;memset(d,0,sizeof(d));memset(s,0,sizeof(s));
55     for(int i=1;i<=m;i++)
56     {
57         int fx=findfa(a[i].x),fy=findfa(a[i].y);
58         if(a[i].c!=a[i-1].c)s[k]=i-1,k++;//记录第k种边的最后一个位置 
59         if(fx!=fy)
60         {
61             fa[fx]=fy;
62             t++;d[k]++;
63         }
64     }
65     s[k]=m;
66     if(t!=n-1){printf("0\n");return 0;}
67     for(int i=1;i<=n;i++)fa[i]=i;
68     int ans=1;
69     for(int i=1;i<=k;i++)
70     {
71         sum=0;
72         dfs(i,0,s[i-1]+1);
73         ans=(ans*sum)%mod;
74         for(int j=s[i-1]+1;j<=s[i];j++)
75         {
76             int fx=findfa(a[j].x),fy=findfa(a[j].y);
77             if(fx!=fy)fa[fx]=fy;
78         }
79     }
80     printf("%d\n",ans);
81     return 0;
82 }

 

以上是关于bzoj1016: [JSOI2008]最小生成树计数(kruskal+dfs)的主要内容,如果未能解决你的问题,请参考以下文章

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

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

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

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

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

bzoj1016[JSOI2008]最小生成树计数