Notes: Kirchhoff's Matrix 基尔霍夫矩阵
Notes: Kirchhoff's Matrix 基尔霍夫矩阵
一般说来,我博客里的 \(\LaTeX\) 通常都没什么用。不过我很高兴,这回不是了。
众所周知地,基尔霍夫矩阵(Kirchhoff's Matrix)是用以解决图上生成树计数问题的。
接下来我们分有向图无向图的情况考虑一下。
无向图上的基尔霍夫矩阵
Theorem
考虑一个含有 \(n\) 个点的无向图 \(G\),我们定义度数矩阵 \(D(G)\) 为:
其中 \(\deg(i)\) 是结点 \(i\) 的度数。
我们定义邻接矩阵 \(A(G)\) 为:
其中 \({\rm edg}(i, j)\) 是结点 \(i\) 与结点 \(j\) 之间连边的数量。
(这显然是我们考虑生成树问题时的关键指标嘛
矩阵树定理指出,如果我们定义基尔霍夫矩阵 \(K(G)\) 为:
那么,取 \(K(G)\) 的任一 \(n - 1\) 阶主子式 \(K'(G) = K(G) \begin{pmatrix} 1 & \dots & i - 1 & i + 1 & \dots n \\ 1 & \dots & i - 1 & i + 1 & \dots n \end{pmatrix}\),
我们有生成树个数 \(ans\) 就是 \(K'\) 的行列式,也即是说:
等价地,设 \(\lambda_1,\lambda_2,\dots,\lambda_{n-1}\) 是 \(K(G)\) 的 \(n - 1\) 个非零特征值,我们也有:
证明留给读者(逃
Hints
主子式:
\(K'(G) = K(G) \begin{pmatrix} 1 & \dots & i - 1 & i + 1 & \dots n \\ 1 & \dots & i - 1 & i + 1 & \dots n \end{pmatrix}\) 表示取矩阵 \(K(G)\) 的
第 \(1,\dots,i-1,i+1,\dots,n\) 行,
与第 \(1,\dots,i-1,i+1,\dots,n\) 构成的子矩阵。
取出 \(k\) 行 \(k\) 列的子矩阵被称为原矩阵的 \(k\) 阶主子式。
行列式的求法:
定义是这样:
其中 \(S\) 是所有 \(1\sim n\) 的排列构成的集合,\(s_i\) 表示排列 \(s\) 中的第 \(i\) 个数。
其中 \({\rm sgn}(s)\) 表示 \(s\) 中逆序对数量的奇偶性,奇数为 0 ,偶数为 1 。
这个定义复杂得几乎不可求,有时我们会选择将行列式展开求解:
考虑行列式:
我们把 \(A\) 的第 \(i\) 行与第 \(j\) 列去掉后留下了的行列式称为 \(a_{ij}\) 的余子式,记作 \(M_{ij}\) 。
然后定义一个叫做代数余子式的东西 \(A_{ij} = (-1)^{i+j} M_{ij}\) ,
如果选定固定的一行 \(k\) ,行列式的值 \(D\) 就满足
选定固定的一行 \(k\) 也是一样的:
证明显然。
不过行列式展开还是太烦了,我们还有别的招。
我们知道行列式有个性质,就是考虑行列式 \(A\) 的任意两个行向量 \(v_i,v_j\) (列向量也一样,略)
若进行操作令 \(v_i = v_i + k \cdot v_j\) 行列式的值不变。
于是我们可以高斯消元把原行列式化成行列梯式(简单理解为对角线的某一侧全都是 0 )
显然,
这个复杂度是 \(O(n^3)\) 的,完全可以接受。
class Matrix {
#define rep(a, b, c) for(int a = b; a <= c; ++a)
private:
vector<vector<double> > mat;
public:
inline void init(int n) {
mat.resize(n + 1);
for(int i = 1; i <= n; ++i)
mat[i].resize(n + 1);
}
int length() {
return mat.size() - 1;
}
double &operator () (int i, int j) {
return mat[i][j];
}
double det() {
int n = length();
rep(i, 1, n) {
int p = i;
rep(j, i + 1, n)
if(fabs(mat[j][i]) > fabs(mat[p][i])) p = j;
if(p != i) {
rep(j, i ,n) swap(mat[i][j], mat[p][j]);
}
rep(j, i + 1, n) {
double tmp = mat[j][i] / mat[i][i];
rep(k, 1, n) mat[j][k] -= mat[i][k] * tmp;
}
}
double ans = 1;
for(int i = 1; i <= n; ++i)
ans *= mat[i][i];
return ans;
}
};
特征值的求法:
其实我不太会。上网找到一篇 https://zhuanlan.zhihu.com/p/61363638 大家可以参考。
高斯消元:
代码见上,不懂可参见苏教版数学必修三或百度。
有向图上的基尔霍夫矩阵
Theorem
有向图上结点的度分为入度和出度,很自然地,我们定义入度矩阵和出度矩阵:
不用说,其中 \({\rm deg^{out}}(i)\) 为结点 \(i\) 的出度,\({\rm deg^{in}}(i)\) 为结点 \(i\) 的入度。
邻接矩阵定义不变:
同样定义出入度基尔霍夫矩阵:
接下来……
等等,还没定义有向图上的生成树吧?
我们记 \(ans_f\) 表示所有边都从儿子指向父亲的生成树个数, \(ans_s\) 表示所有边都从父亲指向儿子的生成树个数。
类似地有:
其中 \(i\) 是根节点的编号,求总数你得枚举做 \(\sum\)
证明留给读者。