• 使用Matrix-tree与它的行列式来解决生成树计数问题


    我又把Matrix写错啦


    这东西讲课的时候竟然一笔带过了,淦

    好吧这东西我不会证

    那我们来愉快的看结论吧

    啦啦啦

    预备工作

    你有一个 $ n $ 个点的图

    比如说

       5
      /|
     / | 
    2--1--3
         |
         |
          4
    

    现在造一个$ n imes n $的矩阵

    我们把他叫做$ D $

    $ D $的元素有这样的一个规律:

    对于某一个$ D_{i,j} $,如果 $ i = j $ ,它就等于点 $ i $ 的度数,否则就为 $ 0 $

    那么我们可以yy出D的样子

    [ D=left[ egin{matrix} 4 & 0 & 0 & 0 & 0 \ 0 & 2 & 0 & 0 & 0 \ 0 & 0 & 3 & 0 & 0 \ 0 & 0 & 0 & 2 & 0 \ 0 & 0 & 0 & 0 & 3 \ end{matrix} ight] ]

    除此之外我们还需要一个矩阵$ A $

    就是邻接矩阵,直接拿来用就可以了

    [ A=left[ egin{matrix} 0 & 1 & 1 & 1 & 1 \ 1 & 0 & 0 & 0 & 1 \ 1 & 0 & 0 & 1 & 1 \ 1 & 0 & 1 & 0 & 0 \ 1 & 1 & 1 & 0 & 0 \ end{matrix} ight] ]

    Now I have a D

    I have an A

    Ah~

    $ D - A $!

    [ D-A=left[ egin{matrix} 4 & -1 & -1 & -1 & -1 \ -1 & 2 & 0 & 0 & -1 \ -1 & 0 & 3 & -1 & -1 \ -1 & 0 & -1 & 2 & 0 \ -1 & -1 & -1 & 0 & 3 \ end{matrix} ight] ]

    依照数学的一贯尿性习惯

    我们把$ D - A $起个名字吧

    叫做鸡儿hop夫基尔霍夫Kirchhoff矩阵K,$ K = D - A $

    关于行列式

    对于一个无向图 G ,它的生成树个数等于其基尔霍夫Kirchhoff矩阵任何一个N-1阶主子式的行列式的绝对值

    上面那个是真-结论

    你问我什么是行列式?

    我们本来写矩阵不是

    [ K=left[ egin{matrix} 4 & -1 & -1 & -1 & -1 \ -1 & 2 & 0 & 0 & -1 \ -1 & 0 & 3 & -1 & -1 \ -1 & 0 & -1 & 2 & 0 \ -1 & -1 & -1 & 0 & 3 \ end{matrix} ight] ]

    的么

    我们把$ [ ] $换成 $ | | $ 就好了
    (这可能不符合数学的严谨性)
    (只在矩阵$ n = m $时有效)

    [ K=left| egin{matrix} 4 & -1 & -1 & -1 & -1 \ -1 & 2 & 0 & 0 & -1 \ -1 & 0 & 3 & -1 & -1 \ -1 & 0 & -1 & 2 & 0 \ -1 & -1 & -1 & 0 & 3 \ end{matrix} ight| ]

    了解更多

    你问我什么是$ x $阶主子式?

    就在 $ [1,n] $ 里面随便选个数 $ p $ ,选 $ (n-x) $ 次,把行列式里面的第 $ p $ 行和第 $ p $ 列同时删掉就好了

    比如 $ K $ 的某个 $ n - 1 $ 阶主子式长这样:

    [ tmp=left| egin{matrix} 4 & -1 & -1 & -1 \ -1 & 2 & 0 & 0 \ -1 & 0 & 3 & -1 \ -1 & 0 & -1 & 2 \ end{matrix} ight| ]

    行列式求值的问题

    行列式的值记为$ det(A) $

    方法你们都看过了

    就是

    • 枚举 $ [1,n] $ 的所有排列,把它叫做 $ b $
    • 把 $ b $ 的逆序对数量求出来叫做 $ r $
    • 然后 $ det(A) = sum (-1)^{r} imes A_{1,b_{1}} imes A_{2,b_{2}} imes ... imes A_{n,b_{n}} $

    不过这样的复杂度肯定非常高

    但我们有一种更好的方法

    我们可以利用行列式的这些性质:

    • 行列式 $ A $ 中某行/列用同一数 $ k $ 乘,其det结果等于 $ kA $
    • 行列式 $ A $ 的det等于其转置行列式 $ A^T $ 的( $ A^T $ 的第i行为 $ A $ 的第i列)
    • 行列式 $ A $ 中两行/列互换,其det会变成原来的相反数。
    • 把行列式 $ A $ 的某行/列中各个数同乘一数后加到另一行/列中各对应数上,结果不会变
    • 行列式中某行/列有公因子,这个公因子可以提到行列式外面去

    来把行列式变成上三角行列式(其实下三角也一样)

    去看一看上三角行列式

    至于怎么用我们亲爱的C++来写这东西

    实现起来就是这个样子(*内部写了取模)

    typedef long long lint;
    const int _ = 202;
    lint deter(lint a[_][_],int n,lint mo)
    {
    	register int i,j,k;
    	register lint tmp,ans=1;
    	for(i=1;i<=n;i++)for(j=1;j<=n;j++)a[i][j]%=mo;
    	for(i=1;i<=n;i++)
    	{
    		for(j=i+1;j<=n;j++)
    		{
    			while(a[j][i]!=0)
    			{
    				tmp=a[i][i]/a[j][i];
    				for(k=1;k<=n;k++)a[i][k]=(a[i][k]-a[j][k]*tmp+mo)%mo;
    				swap(a[i],a[j]),ans=-ans;
    			}
    		}
    		ans=(ans*a[i][i]+mo)%mo;
    		if(ans==0)return 0;
    	}
    	return (ans+mo)%mo;
    }
    
  • 相关阅读:
    简单线程池的设计
    MFC开发--截图工具
    Win32小游戏--蜘蛛纸牌
    C++语言动态创建对象
    C++语言类之间的关系
    c++语言虚函数实现多态的原理(更新版)
    5-24 c++语言之【基础知识】
    小细节--关于printf的输出问题
    Win32小游戏--贪吃蛇
    2020北大夏令营 终末游记
  • 原文地址:https://www.cnblogs.com/finder-iot/p/8662187.html
Copyright © 2020-2023  润新知