无向图生成树计数 -- Kirchhoff 矩阵法模板
Kirchhoff 矩阵法是根据Matrix-Tree定理来的,本人太菜,没有那个心力去看证明了,知道是用就可以了
作用:
给定一个n个点m条边的无向图,求出这个图的生成树的总数。
Matrix-Tree定理(Kirchhoff 矩阵-树定理)
1、G 的度数矩阵 D[G]是⼀个 n*n 的矩阵,并且满⾜:当 i≠j 时,dij=0;当 i=j 时,dij 等于 vi 的度数。
2、G 的邻接矩阵 A[G]也是⼀个 n*n 的矩阵, 并且满⾜:如果 vi、vj 之间有边直接相连,则 aij=1,否则为 0。
我们定义 G 的 Kirchhoff 矩阵(也称为拉普拉斯算⼦)C[G]为 C[G]=D[G]-A[G],则Matrix-Tree 定理可以描述为:G 的所有不同的⽣成树的个数等于其 Kirchhoff 矩阵 C[G]任何⼀个 n-1 阶主⼦式的⾏列式的绝对值。所谓 n-1 阶主⼦式,就是对于r(1≤r≤n),将 C[G]的第 r ⾏、第 r 列同时去掉后得到的新矩阵,⽤ Cr[G]表示。
矩阵树方法实现:
实现方法很简单,第一步是构建拉氏矩阵,很简单。难点在于实现求行列式的值。我这里采用矩阵初等变换将矩阵转化为上三角矩阵,这样行列式的值就等于主对角元素乘积。我实现了打印拉氏矩阵C和输出图生成树个数这两个方法,主体程序如下:
#include<bits/stdc++.h>using namespace std;class spanningTreeNum {private:int V = 0; // 顶点数vector<vector<int> > c; // 拉式矩阵c=d-A
public:spanningTreeNum(int V){this->V = V;c = vector<vector<int> >(V, vector<int>(V, 0)); //初始化二维矩阵c为0}void addEdge(int u, int v); // u和v之间加一条边int getTreeNum();int det(vector<vector<float> > A); // 求行列式A的值void showC();
};void spanningTreeNum::addEdge(int u, int v) {c[u][u]++; // 顶点度数加一c[v][v]++;c[u][v] = -1; // 表示顶点u、v之间有一条边,因为c=d-A,所以为-1c[v][u] = -1;
}int spanningTreeNum::det(vector<vector<float> > A) {/** 思路是将利用初等变换A转化为上三角矩阵,这样对角线元素乘积即为行列式值*/float res = 1;int iter = 0; // 记录交换次数for (int i = 0; i < A.size(); ++i) { //该for循环内的逻辑是将矩阵转化为上三角矩阵if(A[i][i]==0) {for (int j = i; j < A.size(); ++j) {if(A[j][i]!=0) {swap(A[i], A[j]);iter++;}}}for (int j = i+1; j < A.size(); ++j) {float temp = -A[j][i]/A[i][i];for (int k = 0; k < A[j].size(); ++k) {A[j][k] = A[i][k]*temp+A[j][k];}}}for (int i = 0; i < A.size(); ++i) {res *= A[i][i];}if(iter%2==1) res = -res;return (int)res;
}
int spanningTreeNum::getTreeNum() {// 求余子式vector<vector<float > > temp(V-1, vector<float >(V-1, 0));for (int i = 1; i < V; ++i) {for (int j = 1; j < V; ++j) {temp[i-1][j-1] = c[i][j];}}return det(temp);
}void spanningTreeNum::showC() {for (int i = 0; i < c.size(); ++i) {for (int j = 0; j < c[i].size(); ++j) {printf("%3d ", c[i][j]);}cout << endl;}
}int main()
{spanningTreeNum G(4);G.addEdge(0, 1);G.addEdge(0, 2);G.addEdge(1, 2);G.addEdge(2, 3);cout << "拉氏矩阵为:" << endl;G.showC(); //打印拉式矩阵Ccout << "生成树个数为:" << G.getTreeNum() << endl; // 打印生成树个数return 0;
}
运行结果:
无向图生成树计数 -- Kirchhoff 矩阵法模板相关推荐
- 【矩阵乘法】生成树计数(luogu 2109/NOI 2007)
生成树计数 luogu 2109 题目大意 有n个排成一列的点,把距离不超过k的点之间连边,问这个图的生成树个数 输入样例 3 5 输出样例 75 样例说明 样例对应的图如下: 数据范围 解题思路 因 ...
- Matrix-Tree (生成树计数)
生成数计数 对于一个无向简单图,nnn个点和n−1n-1n−1条边构成一个生成树,生成树计数就是求这个无向图中一共有几种不同的生成树(任意两边不同) 度矩阵 n×nn × nn×n 的矩阵,统计每个点 ...
- 生成树计数Matrix-Tree定理-数学
https://www.cnblogs.com/zj75211/p/8039443.html 度数矩阵减去邻接矩阵 再求去掉一行一列的行列式 生成树计数问题: 对于一个有n个点的无向图,由图中n-1条 ...
- java tree degree_生成树计数-Matrix-Tree定理
/* *算法引入: *给定一个无向图G,求它生成树的个数t(G); * *算法思想: *(1)G的度数矩阵D[G]是一个n*n的矩阵,并且满足:当i≠j时,dij=0;当i=j时,dij等于vi的度数 ...
- bzoj1002 生成树计数 找规律
这道题第一眼是生成树计数,n是100,是可以用O(n^3)的求基尔霍夫矩阵的n-1阶的子矩阵的行列式求解的,但是题目中并没有说取模之类的话,就不好办了. 用高精度?有分数出现. 用辗转相除的思想,让它 ...
- 最短路径生成树计数+最短路径生成树
最短路径生成树计数. 我们应该先明白什么是最短路径生成树,不会戳这里. 计数方法明显是要使用乘法原理计数,也就是说我们可以得出每一步的方案数再乘进答案中. 接下来考虑如何的出每一步的方案数,所谓方案数 ...
- 图论 —— 生成树 —— 生成树计数
[概述] 给出一个由 n 个点和 m 条边构成的简单无向加权图,有时需要对生成树计数或对最小生成树计数. 当对生成树计数时,利用基尔霍夫矩阵的 Matrix-Tree 定理即可解决,而对最小生成树计数 ...
- HDU 4305 Lightning (高斯消元解kirchhoff矩阵+逆元)
题意是:给一些坐标点,如果两点之间的距离小于R,并且两点之间没有其他点,则这两个点保持连通,这样构成了一个图.问这个图中生成树的个数. 因为数据量并不大,O(N^3)的建图没有问题. 建好图以后就可以 ...
- Ural 1627 Join(生成树计数)
http://acm.timus.ru/problem.aspx?space=1&num=1627 生成树计数的题,直接用Matrix-Tree定理就可以解决问题了. 代码如下: View C ...
最新文章
- Android Studio 打开提示Invalid Gradle JDK configuration found错误
- CentOS+Nginx+Tomcat+Mysql+PHP 环境搭建及系统部署
- 007_html头部元素
- 如何编写第三方接口_Python接口测试之数据驱动
- Java类集框架 —— HashMap源码分析
- 137. 只出现一次的数字 II
- eclipse检测不到android的手机
- VCenter配置ESXI主机syslog日志收集
- IE下angularJS页面跳转的bug
- [转]ExtJS的使用方法汇总—配置和表格控件使用
- rsa加解密及加签验签
- 商城管理系统(前台+后台+管理员+用户+html+jsp)
- java连接数据库(sqlserver和mysql)
- Arcgis如何使用三调数据统计土地三大类
- 单项选择题标准化考试系统
- 菜鸟教程:Js数据类型
- Qt获取键盘按键ctrl和alt以及shift按键按下和松开
- LSL-- Flow Control
- 2023最新最全git安装教程,保姆级手把手式安装!!!
- 编译原理期末复习—第一章概论