首页 > 代码库 > BZOJ 1016 JSOI2008 最小生成树计数 Kruskal
BZOJ 1016 JSOI2008 最小生成树计数 Kruskal
题目大意:给定一个无向图,求最小生成树的方案数
首先对于一个无向图的最小生成树,每种边权的边的数量是一定的
首先我们先跑一遍Kruskal,求出最小生成树上每种边权的出现次数
然后对于每种出现在最小生成树上的边权,我们从小到大处理
对于每种边权,我们枚举这种边权的边有多少种方案可以加进最小生成树上而不形成环 这个用状压处理
ans乘上这个值 然后把这种边权连接的所有联通块缩点
注意最小生成树不存在时输出0
#include<map> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 1010 #define Mo 31011 using namespace std; struct edge{ int x,y,f; bool operator < (const edge &z) const { return f < z.f ; } }edges[M]; int n,m,ans=1,fa[110]; int digit[M+100]; map<int,int>a; int Find(int x) { if(!fa[x]||fa[x]==x) return fa[x]=x; return fa[x]=Find(fa[x]); } void Kruskal() { int i,cnt=0; memset(fa,0,sizeof fa); for(i=1;i<=m;i++) { int x=Find(edges[i].x),y=Find(edges[i].y); if(x==y) continue; fa[x]=y; cnt++;a[edges[i].f]++; } if(cnt!=n-1) { puts("0"); exit(0); } } int Deal(int x) { int i,j,y,re=0,cnt=a[edges[x].f]; for(y=x;edges[y].f==edges[y+1].f;y++); for(i=0;i<1<<y-x+1;i++) if(digit[i]==cnt) { int temp=i; memset(fa,0,sizeof fa); for(j=x;temp;temp>>=1,j++) if(temp&1) { int xx=Find(edges[j].x); int yy=Find(edges[j].y); if(xx==yy) break; fa[xx]=yy; } if(!temp) ++re; } ans*=re,ans%=Mo; memset(fa,0,sizeof fa); for(i=x;i<=y;i++) { int xx=Find(edges[i].x),yy=Find(edges[i].y); if(xx==yy) continue; fa[xx]=yy; } for(i=y+1;i<=m;i++) edges[i].x=Find(edges[i].x),edges[i].y=Find(edges[i].y); return y; } int main() { int i; for(i=0;i<1<<10;i++) digit[i]=digit[i>>1]+(i&1); cin>>n>>m; for(i=1;i<=m;i++) scanf("%d%d%d",&edges[i].x,&edges[i].y,&edges[i].f); sort(edges+1,edges+m+1); Kruskal(); for(i=1;i<=m;i++) if(a[edges[i].f]) i=Deal(i); cout<<ans<<endl; return 0; }
BZOJ 1016 JSOI2008 最小生成树计数 Kruskal
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。