分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > IT知识

bzoj 1016: [JSOI2008]最小生成树计数【dfs+克鲁斯卡尔】

发布时间:2023-09-06 02:02责任编辑:蔡小小关键词:暂无标签

有一个性质就是组成最小生成树总边权值的若干边权总是相等的
这意味着按边权排序后在权值相同的一段区间内的边能被选入最小生成树的条数是固定的
所以先随便求一个最小生成树,把每段的入选边数记录下来
然后对于每一段dfs找合法方案即可,注意dfs中需要退回并查集,所以用不路径压缩的并查集
然后根据乘法定理,把每一段dfs后的结果乘起来即可。

#include<iostream>#include<cstdio>#include<algorithm>using namespace std;const int N=1005,mod=31011;int n,m,ans=1,sum,tot,cnt,l[N],r[N],c[N],f[N];struct qwe{ ???int u,v,w;}a[N];bool cmp(const qwe &a,const qwe &b){ ???return a.w<b.w;}int zhao(int x){ ???return x==f[x]?x:zhao(f[x]);}void dfs(int q,int w,int k){ ???if(w==r[q]+1) ???{ ???????if(k==c[q]) ???????????sum++; ???????return; ???} ???int fu=zhao(a[w].u),fv=zhao(a[w].v); ???if(fu!=fv) ???{ ???????f[fu]=fv; ???????dfs(q,w+1,k+1); ???????f[fu]=fu,f[fv]=fv; ???} ???dfs(q,w+1,k);}int main(){ ???scanf("%d%d",&n,&m); ???for(int i=1;i<=m;i++) ???????scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w); ???sort(a+1,a+1+m,cmp); ???for(int i=1;i<=n;i++) ???????f[i]=i; ???for(int i=1;i<=m;i++) ???{ ???????if(a[i].w!=a[i-1].w) ???????????r[cnt]=i-1,l[++cnt]=i; ???????int fu=zhao(a[i].u),fv=zhao(a[i].v); ???????if(fu!=fv) ???????????tot++,c[cnt]++,f[fu]=fv; ???} ???if(tot!=n-1) ???{ ???????puts("0"); ???????return 0; ???} ???r[cnt]=m; ???for(int i=1;i<=n;i++) ???????f[i]=i; ???for(int i=1;i<=cnt;i++) ???{ ???????sum=0; ???????dfs(i,l[i],0); ???????ans=ans*sum%mod; ???????for(int j=l[i];j<=r[i];j++) ???????{ ???????????int fu=zhao(a[j].u),fv=zhao(a[j].v); ???????????if(fu!=fv) ???????????????f[fu]=fv; ???????} ???} ???printf("%d\n",ans); ???return 0;}

bzoj 1016: [JSOI2008]最小生成树计数【dfs+克鲁斯卡尔】

原文地址:https://www.cnblogs.com/lokiii/p/9248995.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved