Luogu6178 【模板】Matrix-Tree 定理

https://www.luogu.com.cn/problem/P6178

矩阵树定理

记住结论\(QAQ\)

\(D\)为度数矩阵

\(A\)为邻接矩阵

外向树:边的方向为根指向子节点

内向树:边的方向为子节点指向根

若边权为\(cost\)

那么所有生成树的边权乘积的和如下:

无向图:

\(D\):存在边\(i-j\),则\(D_{i,i}+=cost,D_{j,j}+=cost\),对于\(D_{i,j}(i \ne j)\),\(D_{i,j}=0\)

\(A\):存在边\(i-j\)\(a_{i,j}=a_{j,i}=cost\),否则\(a_{i,j}=a_{j,i}=0\)

有向图:

\(D\):存在边\(i \rightarrow j\),则:

外向树:\(D_{j,j}+=cost\)
内向树:\(D_{i,i}+=cost\)

\(A\):存在边\(i \rightarrow j\)\(a_{i,j}=cost\),否则\(a_{i,j}=0\)

\(C=D-A\)

无向图中:

答案为\(C\)对于任意的\(r\),划去第\(r\)行,第\(r\)列得到的\(n-1\)阶余子式的行列式值

有向图中:

答案为\(C\)对于根节点\(r\),划去第\(r\)行,第\(r\)列得到的\(n-1\)阶余子式的行列式值

若要计算生成树个数,设边权为\(1\)即可

注意,计算行列式时,高斯-约旦消元要保留行列式的上三角(改一下参数就好了),而且交换两行时,行列式的值要变号

\(C++ Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define ll long long
#define N 305
#define p 1000000007
using namespace std;
int x,y,z,n,m,t;
ll a[N][N],ans=1;
ll ksm(ll x,ll y)
{
    ll ans=1;
    while (y)
    {
        if (y & 1)
            ans=ans*x%p;
        x=x*x%p;
        y >>=1;
    }
    return ans;
}
#define inv(x) ksm(x,p-2)
void Gauss()
{
    for (int i=2;i<=n;i++)
    {
        int mx=i;
        for (int j=i+1;j<=n;j++)
            if (!a[i][i] && a[j][i])
            {
                mx=j;
                break;
            }
        if (!a[mx][i])
        {
            ans=0;
            return;
        }
        if (mx!=i)
        {
            for (int j=1;j<=n;j++)
                swap(a[mx][j],a[i][j]);
            ans=-ans;
        }
        for (int j=i;j<=n;j++)
            if (j!=i)
            {
                ll t=a[j][i]*inv(a[i][i])%p;
                for (int k=i;k<=n;k++)
                    (a[j][k]-=t*a[i][k])%=p;
            }
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&t);
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        switch (t)
        {
            case 0:
                (a[x][x]+=z)%=p;
                (a[y][y]+=z)%=p;
                (a[x][y]-=z)%=p;
                (a[y][x]-=z)%=p;
                break;
            case 1:
                (a[y][y]+=z)%=p;
                (a[x][y]-=z)%=p;
                break;
        }
    }
    Gauss();
    for (int i=2;i<=n;i++)
        ans=ans*a[i][i]%p;
    ans=(ans%p+p)%p;
    printf("%lld\n",ans);
    return 0;
}
posted @ 2020-08-04 19:35  GK0328  阅读(131)  评论(0编辑  收藏  举报