BZOJ 1016--最小生成树计数(深搜&kruskal)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1016--最小生成树计数(深搜&kruskal)相关的知识,希望对你有一定的参考价值。
想我这样的zz根本不会矩阵树。。。。。
题目链接:
http://www.lydsy.com/JudgeOnline/problem.php?id=1016
Solution
首先,如果用上所有边都做不出最小生成树,答案显然是0。。
然后,对于一个图的所有最小生成树,他们有的权值为w的边数一定是一样多的。。
所以先求出一个最小生成树,然后把其中一条边去掉,再搜索一下在相同权值的边中是否仍然可以保持连通性。
根据乘法原理求出答案。。。
然后就没有然后了。。。
代码
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> #define M 1010 #define mod 31011 using namespace std; int n,m,cnt,tot; int f[M],w[M],sum[M]; bool c[M]; struct edge{ int l,r,w; }e[M],a[M]; bool cmp(edge p,edge q){return p.w<q.w;} int find(int x){ if(f[x]==x) return f[x]; return find(f[x]); } void RE(){for(int i=1;i<=n;i++) f[i]=i;} void dfs(int x,int now,int k){ if(now==a[x].r+1){ if(k==a[x].w)tot++; return; } int xx=find(e[now].l),yy=find(e[now].r); if(xx!=yy){ f[xx]=yy; dfs(x,now+1,k+1); f[xx]=xx;f[yy]=yy; } dfs(x,now+1,k); } int main(){ int ans=1; cnt=0;tot=0; int xx,yy; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d%d",&e[i].l,&e[i].r,&e[i].w); sort(e+1,e+1+m,cmp); RE(); for(int i=1;i<=m;i++){ if(e[i].w!=e[i-1].w){a[cnt].r=i-1;cnt++;a[cnt].l=i;} xx=find(e[i].l);yy=find(e[i].r); if(xx!=yy){f[xx]=yy;a[cnt].w++;tot++;} } a[cnt].r=m; if(tot+1!=n){printf("0\n");return 0;} RE(); for(int i=1;i<=cnt;i++){ tot=0; dfs(i,a[i].l,0); ans=(ans*tot)%mod; for(int j=a[i].l;j<=a[i].r;j++){ xx=find(e[j].l);yy=find(e[j].r); if(xx!=yy) f[xx]=yy; } } printf("%d\n",ans); return 0; }
This passage is made by Iscream-2001.
以上是关于BZOJ 1016--最小生成树计数(深搜&kruskal)的主要内容,如果未能解决你的问题,请参考以下文章