BZOJ 1016 最小生成树计数 【模板】最小生成树计数

【题解】

对于不同的最小生成树,每种权值的边使用的数量是一定的,每种权值的边的作用是确定的

我们可以先做一遍Kruskal,求出每种权值的边的使用数量num

再对于每种权值的边,2^num搜索出合法使用方案,把每种权值的边的方案用乘法原理乘起来就是答案了

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int maxn=2000,Mod=31011;
 5 int n,m,tot,sum,ans=1,cnt,st[maxn],fa[maxn],num[maxn];
 6 struct edge{int x,y,dis,pos;}e[maxn];
 7 void read(int &k){
 8     k=0; int f=1; char c=getchar();
 9     while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
10     while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar();
11     k*=f;
12 }
13 int find(int x){return fa[x]==x?x:find(fa[x]);}
14 void dfs(int kind,int now,int chosen){
15     if (now==st[kind+1]){
16         if (chosen==num[kind]) sum++;
17         return;
18     }
19     int p=find(e[now].x),q=find(e[now].y);
20     if (p!=q) fa[p]=q,dfs(kind,now+1,chosen+1),fa[p]=p,fa[q]=q;    
21     dfs(kind,now+1,chosen);
22 }
23 bool cmp(edge a,edge b){return a.dis<b.dis;}
24 int main(){
25     read(n); read(m);
26     for (int i=1;i<=m;i++)read(e[i].x),read(e[i].y),read(e[i].dis);
27     sort(e+1,e+m+1,cmp);
28     for (int i=1;i<=m;i++) {
29         if (e[i].dis!=e[i-1].dis) st[++cnt]=i;
30         e[i].pos=cnt;
31     }
32     st[cnt+1]=m+1;
33     for (int i=1;i<=n;i++) fa[i]=i;
34     for (int i=1,x,y;i<=m;i++) 
35         if ((x=find(e[i].x))!=(y=find(e[i].y))) fa[x]=y,num[e[i].pos]++,tot++;
36     if (tot!=n-1) return puts("0"),0;
37     for (int i=1;i<=n;i++) fa[i]=i;
38     for (int i=1;i<=cnt;i++) if(num[i]){
39         sum=0; dfs(i,st[i],0);
40         for (int j=st[i];j<st[i+1];j++) fa[find(e[j].x)]=find(e[j].y);
41         ans=1LL*ans*sum%Mod;
42     }
43     printf("%d",ans);
44     return 0;
45 }
View Code
原文地址:https://www.cnblogs.com/DriverLao/p/7741122.html