[BZOJ1016][JSOI2008]最小生成树计数

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

先总结一下MST的性质吧:

1.(圈性质)考虑一条非树边和一些树边构成的环,环上所有树边的权值一定不大于这条非树边。

2.(割性质)考虑图的一个割,这个割中的最小边一定被选入了MST。

3.考虑同一张图的两个不同MST A和B,将两个MST的边分别从小到大排列,则每对同一位置的边权都是相等的。

4.从小到大将MST加入到图中,在加完任一权值的所有边后,图的连通性是固定的。

 

考虑利用这些定理,根据(3)和(4),我们只要先求出一个MST,就能知道每种权值的边在MST中要出现多少次,以及每种边权的边全部加完后图的连通块个数。有了这些信息,我们只需要对于每种权值搜索选取哪些边,然后用乘法原理即可得到答案。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 4 using namespace std;
 5 
 6 const int N=1010,mod=31011;
 7 int n,m,ans=1,sm,cnt,tot,fa[N],sz[N];
 8 struct E{ int u,v,w; }e[N];
 9 struct P{ int l,r,v; }a[N];
10 
11 inline int rd(){
12     int x=0; char ch=getchar();
13     while (ch<'0' || ch>'9') ch=getchar();
14     while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
15     return x;
16 }
17 
18 bool cmp(E a,E b){ return a.w<b.w; }
19 int find(int x){ return (x==fa[x]) ? x : find(fa[x]); }
20 
21 void dfs(int x,int now,int k){
22     if (now==a[x].r+1){
23         if (k==a[x].v) sm++;
24         return;
25     }
26     int p=find(e[now].u),q=find(e[now].v);
27     if (p!=q){
28         if (sz[p]<sz[q]) swap(p,q);
29         fa[p]=q; sz[q]+=sz[p];
30         dfs(x,now+1,k+1);
31         fa[p]=p; sz[q]-=sz[p];
32     }
33     dfs(x,now+1,k);
34 }
35 
36 int main(){
37     freopen("bzoj1016.in","r",stdin);
38     freopen("bzoj1016.out","w",stdout);
39     n=rd(); m=rd();
40     rep(i,1,n) fa[i]=i,sz[i]=1;
41     rep(i,1,m) e[i].u=rd(),e[i].v=rd(),e[i].w=rd();
42     sort(e+1,e+m+1,cmp);
43     rep(i,1,m){
44         if (e[i].w!=e[i-1].w) a[cnt].r=i-1,a[++cnt].l=i;
45         int p=find(e[i].u),q=find(e[i].v);
46         if (p==q) continue;
47         a[cnt].v++; tot++;
48         if (sz[p]>sz[q]) swap(p,q);
49         fa[p]=q; sz[q]+=sz[p];
50     }
51     a[cnt].r=m;
52     if (tot!=n-1){ puts("0"); return 0; }
53     rep(i,1,n) fa[i]=i,sz[i]=1;
54     rep(i,1,cnt){
55         sm=0; dfs(i,a[i].l,0); ans=ans*sm%mod;
56         rep(j,a[i].l,a[i].r){
57             int p=find(e[j].u),q=find(e[j].v);
58             if (p==q) continue;
59             if (sz[p]>sz[q]) swap(p,q);
60             fa[p]=q;
61         }
62     }
63     printf("%d\n",ans);
64     return 0;
65 }

 

posted @ 2018-07-09 13:00  HocRiser  阅读(237)  评论(0编辑  收藏  举报