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

题解:

最小生成树的两个性质:

1、边权相等的边的个数一定。

2、做完边权为w的所有边时,图的连通性相同。

 

然后就暴力dfs吧~

 

View Code
  1 #include <cstdio>

  2 #include <iostream>

  3 #include <algorithm>

  4 #include <cstdlib>

  5 #include <cstring>

  6  

  7 #define N 2000

  8 #define M 30000

  9 #define mod 31011

 10  

 11 using namespace std;

 12  

 13 struct KRU

 14 {

 15     int a,b,d;

 16 }kru[M];

 17  

 18 int n,m,fa[N],f2[N],st[M],sum[M],cnt,ans=1,tans;

 19 bool vis[N];

 20  

 21  

 22 inline bool cmp(const KRU &a,const KRU &b)

 23 {

 24     return a.d<b.d;

 25 }

 26  

 27 void read()

 28 {

 29     scanf("%d%d",&n,&m);

 30     for(int i=1;i<=m;i++) scanf("%d%d%d",&kru[i].a,&kru[i].b,&kru[i].d);

 31     sort(kru+1,kru+1+m,cmp);

 32 }

 33  

 34 int findfa(int x)

 35 {

 36     if(x!=fa[x]) fa[x]=findfa(fa[x]);

 37     return fa[x];

 38 }

 39  

 40 int findpa(int x)

 41 {

 42     if(x!=f2[x]) return findpa(f2[x]);

 43     return x;

 44 }

 45  

 46 void dfs(int l,int r,int num)

 47 {

 48     if(num==0) {tans++;return;}

 49     if(l>r) return;

 50     int fx=findpa(kru[l].a),fy=findpa(kru[l].b);

 51     if(vis[kru[l].a]&&vis[kru[l].b]&&fx!=fy)

 52     {

 53         f2[fx]=fy;

 54         dfs(l+1,r,num-1);

 55         f2[fx]=fx;

 56     }

 57     dfs(l+1,r,num);

 58 }

 59  

 60 void work(int x)

 61 {

 62     tans=0;

 63     dfs(st[x],st[x+1]-1,sum[x]);

 64     ans=(ans*tans)%mod;

 65 }

 66  

 67 void kruskal()

 68 {

 69     memset(vis,0,sizeof vis);

 70     for(int i=1;i<=n;i++) fa[i]=f2[i]=i;

 71     int num=1,i;

 72     cnt=0;

 73     for(i=1;i<=m;i++)

 74     {

 75         if(i==1||kru[i].d!=kru[i-1].d)

 76         {

 77             st[++cnt]=i; sum[cnt]=0;

 78             if(i!=1) work(cnt-1);

 79             for(int j=1;j<=n;j++) f2[j]=fa[j];

 80         }

 81         if(findfa(kru[i].a)!=findfa(kru[i].b))

 82         {

 83             num++; sum[cnt]++;

 84             fa[findfa(kru[i].a)]=findfa(kru[i].b);

 85             vis[kru[i].a]=vis[kru[i].b]=true;

 86         }

 87         if(num==n) break;

 88     }

 89     kru[m+1].d=-1;

 90     for(int j=i+1;j<=m+1;j++)

 91         if(kru[j-1].d!=kru[j].d)

 92         {

 93             st[cnt+1]=j;

 94             break;

 95         }

 96     work(cnt);

 97     if(num==n) printf("%d\n",ans);

 98     else printf("0\n");

 99 }

100  

101 int main()

102 {

103     read(),kruskal();

104     return 0;

105 } 

 

 

你可能感兴趣的:(最小生成树)