• 浅谈Matrix-Tree定理


    首先介绍一下Matrix-Tree定理是干什莫用的:

    Matrix-Tree定理用于图的生成树计数。复杂度为 $ O(n^3) $。

    在学习Matrix-Tree定理之前,我们需要先了解离散拉普拉斯算子。

    一.离散拉普拉斯算子

    给定了一个图,我们先求出它的度数矩阵D和邻接矩阵A

    度数矩阵:D[x][x]表示点x的度数,其他元素为0.
    邻接矩阵:A[i][j]代表i到j是否有边,有边则为1,无边则为0.

    由此计算出基尔霍夫矩阵C:C=D-A

    例子:三个点的完全图:

    它的D矩阵(度数矩阵)是:

    2 0 0

    0 2 0

    0 0 2

    它的A矩阵(邻接矩阵)是:

    0 1 1

    1 0 1

    1 1 0

    它的C矩阵(基尔霍夫矩阵)是:

    2 -1 -1

    -1 2 -1

    -1 -1 2

    我们把计算出基尔霍夫矩阵的运算称作离散拉普拉斯算子

    二.Matrix-Tree定理

    Matrix-Tree定理的内容是:

    对于一个基尔霍夫矩阵,随意去掉第r行第r列,留下的这个矩阵的行列式的绝对值,就是生成树的个数。

    一般这样操作:对于一个基尔霍夫矩阵,扔掉最后一行和最后一列,算出它的行列式值即可。

    还是看上面的例子。扔掉最后一行和最后一列,C矩阵变成:

    2 -1

    -1 2

    它的行列式值为2*2-(-1)*(-1)=3.2×2(1)×(1)=3.
    所以这个图共有3个生成树。

    若想知道证明,请参考这里

    三.行列式求值

    如何求行列式的值?

    我们只需要像高斯消元那样,把行列式弄成上三角矩阵,然后算出c[1][1]*c[2][2]*......*c[n][n],它就是行列式的值。

    一个3*3的例子:

    行列式:

    2 -1 -1

    -1 2 -1

    -1 -1 2

    第一次消元后:

    2 -1 -1

    0 3 -3

    0 -3 3

    第二次消元后:

    2 -1 -1

    0 3 -3

    0 0 0

    然后算出2*3*0=0,它就是行列式的值

    附上代码:

    void getValue()
    {
        int a,i,j;
        double v;
    
        for(a=1;a<n;a++)
            for(i=a+1;i<=n;i++)
            {
                v=C[i][a]/C[a][a];
                for(j=a;j<=n;j++)
                    C[i][j]-=v*C[a][j];
            }
    
        v=1;
        for(i=1;i<=n;i++)
            v*=C[i][i];
        if(v<0) v=-v;
    
        printf("%.0f",v);
    }

    一些值得考虑的问题

    如何保证消元的精度?

    采用列主元法消元。
    假设我们现在考虑元p,我们就把p的系数绝对值最大的那一行,拿来消其他的行

    如果消元时遇到所有列都为0怎么办?

    正常情况下,不会遇到这种事情。
    如果遇到了,说明整个图根本不连通,那生成树的个数显然是0了。0

  • 相关阅读:
    IT名词备忘录——汇编
    逆转链表的实现
    编写安全的代码的一些技巧
    extern c 谈
    回调函数
    职场必备八个黄金句型
    CString类的用法介绍和自己动手写的CString类
    61条面向对象设计的经验原则(转贴)
    sprintf的用法
    VisualStudioVS2010统计代码行数
  • 原文地址:https://www.cnblogs.com/jiangminghong/p/10472482.html
Copyright © 2020-2023  润新知