zoukankan      html  css  js  c++  java
  • 矩阵树定理 学习笔记

    Matrix Tree定理

    写在前面的话

    写这篇博客其实写了很久,主要是刚开始的时候太菜了,完全不能完全理解,于是,我写的东西当我变得强一点之后就会发现有点问题,于是就改啊改啊添啊添啊,于是就从刚才开始的那个样子变成了现在这样。

    希望我写的博客能对初学矩阵树定理的同学有一点帮助。

    前置知识:行列式

    行列式的定义

    一个矩阵的行列式定义为:

    [sum_{p} (-1)^{pi (p)} prod_{j=1} A_{j,p_j} ]

    这里的(p)指的是({1,2,3,...,n})的一种排列,(pi (p))指的是(p)的逆序对个数

    行列式的求法

    如果我们直接用暴力的话时间复杂度为(Theta (n imes n!)),但是实际上我们可以对此进行优化。


    性质1

    交换矩阵的任意两行,行列式变号

    我们可以发现交换了两行以后,变化的只有符号位,但是如何说明一定为变成相反数呢?我们发现这个问题只与排列的逆序对数有关,下面引出一个命题来证明。

    定理1

    一个排列交换其中任意两个元素,逆序对个数变化量为奇数

    证明1

    显然。我们可以发现变化量只跟两个元素之间的元素有关,然后就很好证了,这里就不赘述了。

    性质2

    矩阵的一行都乘以(k),行列式也乘以(k)

    证明2

    根据定义公式,显然。

    性质3

    如果矩阵内有两行相等,那么行列式为(0)

    证明3

    因为交换以后要变为相反数,但是可以看出变化前与变化后行列式一样,所以为了满足条件,行列式的值为(0)

    性质4

    如果一行是另一行的(k)倍,那么行列式值为(0)

    证明4

    由性质(2)和性质(3)显然。

    性质5

    一行加上另一行的(k)倍,行列式不变。

    证明5

    可以从行列式定义的式子下手。

    我们可以把现矩阵的行列式拆成两个行列式相加,一个是原先矩阵的行列式,另一个是增长的行列式。

    根据性质(4),可以得到增长的行列式为(0)

    性质6

    一个上三角矩阵的行列式为斜边元素之积。

    证明6

    根据公式显然。


    有了上面的(6)个性质,我们就可以用( ext {Gauss})消元把原矩阵消成一个上三角矩阵,然后就好求了。

    模数非质数时的求法

    如果模数非质数我们就不能直接用费马小定理或者拓展欧几里得了。

    我们可以考虑用类似于辗转相除法的一种做法,我们一直去找其它行来尽可能抵消当前这一行,然后每一次操作就把两行进行一次尽可能的抵消,实际上就是辗转相除法。结局肯定与辗转相除法一样有一行该列终于变成了零。我们发现这个的时间复杂度也是(Theta(n^3log n))的。

    不过还是有(Theta(n^3)),不过因为我太弱了,这里先咕着。

    前置定义:Kirchhoff矩阵

    ( ext {Kirchhoff})矩阵是指的对于一个图构造出来的一个矩阵。具体定义为度数矩阵减去邻接矩阵。

    度数矩阵指的是:

    [A_{i,j}= egin{cases} degree_i,i=j\ 0,i ot= j end{cases}]

    邻接矩阵应该就不用解释了。不过需要注意的是如果有重边的话应该算有多少条。

    Matrix Tree定理

    一个图中的生成树个数等于其( ext {Kirchhoff})矩阵的任意一个 代数余子式的行列式

    Matrix Tree定理的证明

    性质1

    一个图的( ext {Kirchhoff})矩阵行列式为零。

    性质2

    一个图的( ext {Kirchhoff})矩阵的任一代数余子式的行列式相同。

    前置定义

    我们定义一个图的关联矩阵(B)为:

    [forall e_{k}={ u_k,v_k} ]

    [exists B_{k,u_k}=1,B_{k,v_k}=-1 ]

    我们定义一个矩阵(A)的转置矩阵(A^T)为:

    [A^T_{i,j}=A_{j,i} ]

    证明

    首先我们可以得到,对于一个图,设它的( ext {Kirchhoff})矩阵为( ext L),关联矩阵为( ext B),那么有:

    [ ext L= ext B ext B^T ]

    这个很好证明,只需要把式子列出来一下就好了。

    Part(1)

    对于一个非连通图( ext G),(|L|=0)

    证明

    (|L|)(L)的行列式。我们再设(M_i)(L)删去第(i)行第(i)列后得到的矩阵。

    首先,我们考虑把( ext G)视作若干个强连通分量,就叫做(G_1,G_2,G_3,...,G_k)吧。

    那么,我们可以考虑对(L)进行一下交换,把一个联通块内的元素在(L)排在相邻位置。就比如如果(1,2)在同一联通块,我们就可以第一行放(1),第二行放(2)

    那么:

    [L= egin{matrix} G_1 & 0 & 0 & ... & 0\ 0 & G_2 & 0 & ... & 0\ 0 & 0 & G_3 & ... & 0\ ... & ... & ... & ... & ...\ ... & ... & ... & ... & ...\ 0 & 0 & 0 & ... & G_k end{matrix} ]

    我们这个时候可以不去考虑符号位的变化,因为如果(|L|=0)也没有区别。

    我们可以看出:

    [|L|=|G_1| imes |G_2| imes ... imes |G_k| ]

    这个我们可以通过想象高斯消元过程来说明。因为最后消掉以后都是上三角矩阵,那么,对于(forall i,G_i)都是上三角矩阵,那么就满足条件了。

    又因为( ext {Kirchhoff})矩阵的性质(1),所以

    [forall i,|G_i|=0 ]

    所以(|M_i|=|L|=0)

    Part(2)

    我们考虑一棵树(G)

    可以通过数学归纳法说明(|M_i|=1),这里就不赘述了。

    Part(3)

    这里我们首先要提到一个定理: Binet-Cauthy定理


    ( ext{Binet-Cauthy})定理

    (|AB|=sum_{|s|=n} |A_{p}B_{p}|)

    其中(A,B)不一定是方阵。(s)指的是一个从({1,2,3,..,m})中选出的一个集合。(A_p)表示(A)的列中只保留(s)中选中的列留下的矩阵。

    由于作者水平有限,这里没有办法证明。(因为我太菜了)


    那么,我们就可以进行推导了。我们设(B_i)(G)的关联矩阵(B)去掉(i)这一列的矩阵。可以得到:

    [|M_i|=|B_i B^T_i|=sum_{|s|=n-1} |{B_{i}}_p {B^T_i}_p| ]

    根据( ext {Part}2),后面那部分只有在(s)选出来的边构成树的时候为(1),其余时候皆为(0)

    于是原式就等于从( ext G)中选出(n-1)条边组成一棵树的方案数。

    至此,证毕。

    ( ext{Matrix Tree})定理的应用

    ( ext {The 1st})

    题目传送门

    题目大意

    给定一张无向图,求其生成树个数

    ( ext{Solution})

    模板题。用( ext{Matrix Tree})求解即可。不理解( ext {Matrix Tree})定理的也可以通过阅读代码理解。

    ( ext {Code})

    具体实现

    ( ext {The 2nd})

    题目传送门

    题目大意

    (n)个节点,(m)条边,每条边有(p_i)的概率留下来。求最后留下一棵树的概率。

    ( ext{Solution})

    这道题给了我们一个启示,( ext {Matrix Tree})定理其实是可以推广的。推广到一般情况,( ext {Matrix Tree})其实求的是所有可能生成树边权之积的和。

    这道题是求刚好留下一棵生成树的概率,那么,即是求:

    [sum_{ ext {tree}} (prod_{iin ext {tree}} p_i prod_{i ot in ext {tree}}(1-p_i)) ]

    [=sum_{ ext {tree}} (prod_{iin ext {tree}} p_i frac{prod_{i} (1-p_i)}{prod_{iin ext {tree}} (1-p_i)}) ]

    [=prod_{i=1} (1-p_i) sum_{ ext {tree}}{ frac{p_i}{1-p_i}} ]

    这个时候我们只需要把 (frac{p_i}{1-p_i}) 视作第(i)条边的边权即可。那么一个点的度数就是所有以它为端点的边的边权和。

    其实( ext {Matrix Tree})定理还可以推广到有向图里面去,只需要建图的时候有方向性即可。

    ( ext {Code})

    具体实现

    ( ext {The 3rd})

    题目传送门

    题目大意

    (n)个节点若干条条边,有(n-1)个公司,每个公司有可以修的边的名单,求每个公司刚好修一条路修出一棵树的方案数。

    ( ext {Solution})

    这道题有两个限制,那我们就只好考虑容斥了。

    如果我们直接算出(n-1)个公司修铁路的方案数,很显然,我们多算了。因为我们也算上了(n-2)个公司修的方案数,那我们就得减去(n-2)个公司修的方案数,那(n-2)个公司修的方案数又得减去(n-3)个公司修的方案数......以此类推,不难看出这就是个容斥了。

    然后套一下矩阵树定理的板子就好了。

    ( ext{Code})

    具体实现

    ( ext {The 4th})

    题目传送门

    题目大意

    给定一棵(n)个点的数,对于每个(kin [0,n-1]),求出恰好有(k)条边与给定树相同的生成树个数。

    思路

    感谢 @EMT__Mashiro 的点拨。

    我们上文提到了,其实矩阵树定理求的是:

    [sum_{T} prod_{e_i in T} w_{e_i} ]

    (w_i)表示第(i)条边的权值。

    我们对于这道题,我们其实可以发现,如果我们对于在给定树中出现的边赋值为(x),未出现过的赋为(1),那么,对于(kin [0,n-1]),答案就是:

    [[x^k] sum_{T} prod_{e_i in T} w_{e_i} ]

    但是我们显然不可能直接拿矩阵树定理套多项式吧?(常数爆炸警告!)我们可以发现这其实是一个(n-1)次的多项式,于是我们可以选(n)个点求到答案然后用高斯消元求到系数即可。

    ( ext {Code})

    具体实现

    ( ext {The 5th})

    题目传送门

    题目大意

    给出一个图,求出:

    [sum_{T}(sum_{i=1,e_i in T}^{n-1} w_{e_i}) imes gcd(w_{e_1},w_{e_2},w_{e_3},..,w_{e_{n-1}}) ]

    思路

    先讲个特别有趣的事情,这道题其实是(2020)省选( ext {Day2T3}),然后恰好那天luogu日报就是这篇博客。。。

    我们发现其实这个式子可以反演,就可以变成:

    [sum_{T}(sum_{i=1,e_i in T}^{n-1} w_{e_i}) imes sum_{d|w_{e_1},d|w_{e_2},...,d|w_{e_{n-1}}} varphi (d) ]

    [=sum_{d=1} varphi (d) sum_{T} (sum_{i=1,i_i in T,d|w_{e_i}} w_{e_i}) ]

    于是我们的问题就是如何求出后面那个东西,其实我们有了上一道的基础,我们可以把边权设为(1+xw_{e_i}),那么,答案就是一次项的系数了。于是,我们就可以模拟一个一次多项式(Theta(144 n^4))解决了。((sqrt {152501}approx144))但是其实(Theta(144n^4))只是一个上界,实际上远远跑不满,只要剪枝剪得好就可以在(500 ext {ms})左右通过这道题。

    一个小小的拓展

    其实矩阵树定理可以拓展到交换环上的元素。交换环就是说上面的元素都满足交换律。

  • 相关阅读:
    设计模式03
    设计模式02
    设计模式01
    HTTP
    C++ 编程学习(六) 函数
    C++编程学习(五) C++ 存储类
    C++编程学习(四)声明/枚举
    ROS常见问题(一) 安装ROS时sudo rosdep init指令报错 最全解决方法
    ROS常用命令或经常碰到的问题
    Ubuntu16.04 在Windows10 系统下的安装(双系统)
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/13276282.html
Copyright © 2011-2022 走看看