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 }