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 } 

 

 

posted @ 2013-03-05 21:03  proverbs  阅读(955)  评论(0编辑  收藏  举报