【概述】

给出一个由 n 个点和 m 条边构成的简单无向加权图,有时需要对生成树计数或对最小生成树计数。

当对生成树计数时,利用基尔霍夫矩阵的 Matrix-Tree 定理即可解决,而对最小生成树计数时,根据数据范围的不同,所采用的方法也不同。

关于基尔霍夫矩阵:点击这里

【生成树计数】

对于生成树的计数,一般采用矩阵树定理(Matrix-Tree 定理)来解决。

Matrix-Tree 定理的内容为:对于已经得出的基尔霍夫矩阵,去掉其随意一行一列得出的矩阵的行列式,其绝对值为生成树的个数

因此,对于给定的图 G,若要求其生成树个数,可以先求其基尔霍夫矩阵,然后随意取其任意一个 n-1 阶行列式,然后求出行列式的值,其绝对值就是这个图中生成树的个数

LL K[N][N];
LL gauss(int n){//求矩阵K的n-1阶顺序主子式LL res=1;for(int i=1;i<=n-1;i++){//枚举主对角线上第i个元素for(int j=i+1;j<=n-1;j++){//枚举剩下的行while(K[j][i]){//辗转相除int t=K[i][i]/K[j][i];for(int k=i;k<=n-1;k++)//转为倒三角K[i][k]=(K[i][k]-t*K[j][k]+MOD)%MOD;swap(K[i],K[j]);//交换i、j两行res=-res;//取负}}res=(res*K[i][i])%MOD;}return (res+MOD)%MOD;
}
int main(){int n,m;scanf("%d%d",&n,&m);memset(K,0,sizeof(K));for(int i=1;i<=m;i++){int x,y;scanf("%d%d",&x,&y);K[x][x]++;K[y][y]++;K[x][y]--;K[y][x]--;}printf("%lld\n",gauss(n));return 0;
}

【最小生成树计数】

根据给出的 n、m 的数据范围,最小生成树的计数分为简化版、加强版。

最小生成树的计数的核心为 MST 的以下两条性质:

  • 每种权值的边的数量是固定的
  • 不同的生成树中,某一种权值的边任意加入需要的数量后,形成的联通块状态是相同的

1.简化版

当每种权值的边不超过 10 条时,利用 dfs,暴力枚举即可解决,时间复杂度为 

根据最小生成树的性质,先统计出每种权值需要的边的条数 cnt

然后进行 dfs,枚举第 i 种权值的边选择哪 cnt​ 条,然后根据乘法原理来统计答案

需要注意的是,为了能够快速分开连通块,并查集中不能使用路径压缩

struct Edge {int x,y;int dis;bool operator < (const Edge &rhs)const{return dis<rhs.dis;}
} edge[N];
struct build {int l,r;int cnt;
} a[N];
int tot;
int n,m;
int father[N];
int sum;int Find(int x) {if(father[x]!=x)return Find(father[x]);return father[x];
}
void dfs(int x,int now,int num) {if(now==a[x].r+1) {if(num==a[x].cnt)//选指定的条数sum++;return ;}int fx=Find(edge[now].x);int fy=Find(edge[now].y);if(fx!=fy) {//选father[fx]=fy;dfs(x,now+1,num+1);father[fx]=fx;father[fy]=fy;}dfs(x,now+1,num);//不选
}
int Kruskal() {sort(edge+1,edge+m+1);for(int i=1; i<=n; i++)father[i]=i;int cnt=0;for(int i=1; i<=m; i++) {if(edge[i].dis!=edge[i-1].dis) {tot++;a[tot].l=i;a[tot-1].r=i-1;}int x=Find(edge[i].x);int y=Find(edge[i].y);if(x!=y) {father[y]=x;a[tot].cnt++;cnt++;}}a[tot].r=m;return cnt;
}
int main() {scanf("%d%d",&n,&m);int x,y,z;for(int i=1; i<=m; i++)scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].dis);int num=Kruskal();if(num!=n-1) {printf("0");return 0;}else{for(int i=1; i<=n; i++)father[i]=i;int res=1;for(int i=1; i<=tot; i++) {sum=0;dfs(i,a[i].l,0);res=res*sum;for(int j=a[i].l; j<=a[i].r; j++) {int x=Find(edge[j].x);int y=Find(edge[j].y);if(x!=y)father[y]=x;}}printf("%d",res);}return 0;
}

2.加强版

当每种权值的边不超过 100 条,需要利用 Matrix-Tree 定理,时间复杂度为 

根据 MST 的性质,枚举树边的权值 i,将权值不是 i 的树边都加入到图中然后进行缩点。将权值是 i 的原图中的边,在缩点后构造基尔霍夫矩阵,再利用 Matrix-Tree 定理求出方案数。

最终答案根据乘法原理进行计算即可。

struct Edge {int x,y;int dis;bool operator < (const Edge &rhs) const {return dis<rhs.dis;}
} edge[N],tr[N];
int n,m;
int father[N];
int G[N][N];
int tot,bel[N],val[N];
int Find(int x) {if(father[x]!=x)return father[x]=Find(father[x]);return x;
}
int Gauss(int n) {int res=1;for(int i=1; i<=n; i++) {for(int k=i+1; k<=n; k++) {while(G[k][i]) {int d=G[i][i]/G[k][i];for(int j=i; j<=n; j++)G[i][j]=(G[i][j]-1LL*d*G[k][j]%MOD+MOD)%MOD;swap(G[i],G[k]);res=-res;}}res=1LL*res*G[i][i]%MOD,res=(res+MOD)%MOD;}return res;
}
int Kruskal() {sort(edge+1,edge+m+1);for(int i=1; i<=n; i++)father[i]=i;int cnt=0;for(int i=1; i<=m; i++) {int fu=Find(edge[i].x);int fv=Find(edge[i].y);if(fu==fv)continue;father[fu]=fv,tr[++cnt]=edge[i];if(edge[i].dis!=val[tot])val[++tot]=edge[i].dis;}return cnt;
}
void addTreeEdge(int v) {for(int i=1; i<n&&tr[i].dis!=v; i++){int x=tr[i].x;int y=tr[i].y;father[Find(x)]=Find(y);}for(int i=n-1; i&&tr[i].dis!=v; i--){int x=tr[i].x;int y=tr[i].y;father[Find(x)]=Find(y);}
}
void rebuild(int v) {memset(G,0,sizeof(G));for(int i=1; i<=m; i++){if(edge[i].dis==v){int x=bel[edge[i].x];int y=bel[edge[i].y];G[x][y]--;G[y][x]--;G[x][x]++;G[y][y]++;}}
}
int main() {scanf("%d%d",&n,&m);for(int i=1; i<=m; i++)scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].dis);int cnt=Kruskal();if(cnt!=n-1) {printf("0\n");}else{int res=1;for(int i=1; i<=tot; i++) {for(int i=1; i<=n; i++)father[i]=i;addTreeEdge(val[i]);int blo=0;for(int i=1; i<=n; i++)if(Find(i)==i)bel[i]=++blo;for(int i=1; i<=n; i++)bel[i]=bel[Find(i)];rebuild(val[i]);res=1LL*res*Gauss(blo-1)%MOD;}printf("%d\n",res);}return 0;
}

图论 —— 生成树 —— 生成树计数相关推荐

  1. 生成树的计数 Matrix-Tree(矩阵树)定理

    信息学竞赛中,有关生成树的最优化问题如最小生成树等是我们经常遇到的,而对生成树的计数及其相关问题则少有涉及.事实上,生成树的计数是十分有意义的,在许多方面都有着广泛的应用.本文从一道信息学竞赛中出现的 ...

  2. 图论 —— 生成树 —— 生成树计数 —— 基尔霍夫矩阵

    [概述] Matrix-Tree 定理又称基尔霍夫矩阵树定理,其用于解决:给定 n 个点 m 条边的无向图,求图的生成树个数的问题. 其利用线性代数中矩阵的行列式来进行求解,关于矩阵的行列式:点击这里 ...

  3. 图论 ---- CF1495D .BFS Trees(图论最短路生成树+枚举计数+树的层次性)

    题目大意 题目大意: 解题思路: 首先我们肯定先把任意两个点之间的最短路求出来→Floyed\rightarrow Floyed→Floyed最短路算法 现在我们假设只固定两个点x,yx,yx,y去求 ...

  4. [图论]最短路计数(spfa)

    最短路计数 Description 给出一个NN个顶点MM条边的无向无权图,顶点编号为1-N1−N.问从顶点11开始,到其他每个点的最短路有几条. Input 第一行包含22个正整数N,MN,M,为图 ...

  5. STP(生成树协议)总结

    文章目录 一.什么是生成树? 二.生成树的作用 三.生成树的原理和工作过程 3.1.原理 3.2.工作过程(即选举过程) 3.3. 练习:画出这三个图的生成树 四.生成树的要求 五.生成树的类型(五种 ...

  6. 华为HCIA-datacom 学习笔记8——生成树

    华为HCIA-datacom 学习笔记8--生成树 生成树 1.技术背景: 二层交换机网络的冗余性与环路.人为错误导致的二层环路 2.二层环路带来的问题 广播风暴与MAC地址表漂移 3.STP基本概念 ...

  7. 图论算法 最短路程_从网页排序看图论的重要应用

    从网页排序|看图论的重要应用 图,是什么? 现实生活中很多问题都可以用图进行描述, 如网络流.资源分配.电路优化.网页排序.搜索.工序安排等等. 同时, 图也是描述许多数据结构的重要手段, 如树结构是 ...

  8. 图论专题1(网络流)

    推荐阅读: 网络流基础知识和Dinic:http://www.cnblogs.com/SYCstudio/p/7260613.html#3848907 建模:https://www.cnblogs.c ...

  9. 电子科技大学 图论期末复习 公式索引

    title: 图论期末考试复习 date: 2020-08-17 09:01:09 tags: 参考资料:<图论及其应用> 高等教育出版社 张先迪 / 李正良 仅用于方便复习公式查阅,公式 ...

最新文章

  1. android 美颜 技术点,《Android 美颜类相机开发汇总》第六章 Android OpenGLES 美妆定制实现...
  2. 【Android 界面效果9】9patch图片
  3. 时间序列:简易prophet
  4. php 重复区域,如何使用Mysql和PHP从重复区域单击缩略图后检索图像
  5. python测试testsuite使用命令行参数的问题
  6. 路由(二)——动态路由简介与RIP协议
  7. 取消myeclipse2017的Dashboard页面
  8. spring和mybatis结合做简单的增删查改系统_springbootamp;amp;vue简单的景点信息管理系统...
  9. CoAP学习笔记——服务器端繁忙时的处理请求流程
  10. 燃气管理 php,智能燃气管理信息系统设计
  11. linux access源码,从零开始学习Linux:Day04 源码安装Nginx 。acess/status/referer
  12. htc 常见错误和解决方案
  13. PAT a1125
  14. 大数据应用之 --- apache doris 基于ssb测试
  15. 命令与征服4java攻略_《命令与征服4》全关卡任务流程攻略
  16. Encoded password does not look like BCrypt最新异常处理
  17. 安卓手机屏幕镜像显示截取屏幕时没有【不再提示】选项的解决办法
  18. [sig16]Real-time Rendering on a Power Budget
  19. 【期货龙虎榜量价分析】红枣PVC创新高,多空大幅增仓博弈激烈
  20. 计算机水平意见,【要闻】我省从明年起基层评职称对外语和计算机水平不作要求...

热门文章

  1. extjs 日期不显示
  2. 手把手教你用Python给小姐姐美个颜
  3. S5PV210裸机之SD卡
  4. Kafka中副本机制的设计和原理
  5. 2021 元宇宙研究报告!
  6. 「装X指南」:手把手教你包装成程序员大佬
  7. JimuReport 1.3.7 首个正式版本发布,免费的可视化拖拽报表
  8. JeecgBoot 移动OA 新版本出炉,速度体验!!!
  9. 介绍Spring Cloud Stream与RabbitMQ集成
  10. 七步从Angular.JS菜鸟到专家(1):如何开始