zoukankan      html  css  js  c++  java
  • Matrix-Tree 定理小记

    发现身边的神仙们都会矩阵树定理,我这个菜鸡还不会,就来学了一下(

    声明:本文 几乎 没有什么证明,感兴趣的读者可以看 这里

    行列式

    【模板】行列式求值

    定义

    对于一个矩阵 (A_{i,j}),它的行列式 (det(A)=sumlimits_{P}(-1)^{ au(P)}prodlimits_{i=1}^nA_{i,P_i})

    其中 (P)(1sim n) 的一个排列,( au(P))(P) 的逆序对数。

    性质

    1. 上三角矩阵与下三角矩阵的行列式为对角线的乘积;
    2. 交换矩阵两行,矩阵行列式的值变号;
    3. 将矩阵的某一行乘 (k),则矩阵行列式的值也乘 (k)
    4. 矩阵中如果有两行(列)的值相同,则矩阵行列式的值为 (0)
    5. 将矩阵某一行(列)加上另一行(列)的 (k) 倍,行列式的值不变。

    代码

    使用消元法求解。

    #include <bits/stdc++.h>
    #define DEBUG fprintf(stderr, "Passing [%s] line %d
    ", __FUNCTION__, __LINE__)
    #define File(x) freopen(x".in","r",stdin); freopen(x".out","w",stdout)
    #define DC int T = gi <int> (); while (T--)
    
    using namespace std;
    
    typedef long long LL;
    typedef pair <int, int> PII;
    typedef pair <int, PII> PIII;
    
    template <typename T>
    inline T gi()
    {
        T f = 1, x = 0; char c = getchar();
        while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
        while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return f * x;
    }
    
    const int INF = 0x3f3f3f3f, N = 603, M = N << 1;
    
    int n, mod;
    LL a[N][N];
    
    inline LL solve()
    {
    	LL ans = 1, op = 1;
    	for (int i = 1; i <= n; i+=1)
    	{
    		for (int j = i + 1; j <= n; j+=1)
    		{
    			while (a[i][i])
    			{
    				int p = a[j][i] / a[i][i];
    				for (int k = i; k <= n; k+=1)
    				{
    					a[j][k] = ((a[j][k] - 1ll * p * a[i][k]) % mod + mod) % mod;
    					swap(a[i][k], a[j][k]);
    				}
    				op *= -1;
    			}
    			swap(a[i], a[j]);
    			op *= -1;
    		}
    		ans = ans * a[i][i] % mod;
    	}
    	return (ans * op % mod + mod) % mod;
    }
    
    int main()
    { 
        n = gi <int> (), mod = gi <int> ();
        for (int i = 1; i <= n; i+=1) for (int j = 1; j <= n; j+=1) a[i][j] = gi <LL> ();
        printf("%lld
    ", solve());
        return 0;
    }
    

    无向图

    设一张图 (G) 的度数矩阵为 (D),邻接矩阵为 (A)

    易得:

    [D_{i,j}= egin{cases} deg(i)&{i=j}\ 0&{i ot =j} end{cases} ]

    则图的基尔霍夫(Kirchhoff)矩阵 (L=D-A)

    (L') 为基尔霍夫矩阵 (L) 去掉第 (i) 行和第 (i) 列(其中 (1le ile n))得到的新矩阵,则 (det(L')) 即为图 (G) 的生成树个数((det(L')) 为矩阵 (L') 的行列式)。

    有向图

    修改一下度数矩阵 (D) 的定义:

    • 若题目要求的是外向树个数,则 (D) 为入度矩阵,即:

    [D_{i,j}= egin{cases} deg_{in}(i)&{i=j}\ 0&{i ot =j} end{cases} ]

    • 若题目要求的是内向树个数,则 (D) 为出度矩阵,即:

    [D_{i,j}= egin{cases} deg_{out}(i)&{i=j}\ 0&{i ot =j} end{cases} ]

    注意这里依然要去掉一行一列,只是这里去掉的第 (i) 行第 (i) 列就代表生成树的根为 (i)

    代码

    【模板】Matrix-Tree 定理

    #include <bits/stdc++.h>
    #define DEBUG fprintf(stderr, "Passing [%s] line %d
    ", __FUNCTION__, __LINE__)
    #define File(x) freopen(x".in","r",stdin); freopen(x".out","w",stdout)
    #define DC int T = gi <int> (); while (T--)
    
    using namespace std;
    
    typedef long long LL;
    typedef pair <int, int> PII;
    typedef pair <int, PII> PIII;
    
    template <typename T>
    inline T gi()
    {
        T f = 1, x = 0; char c = getchar();
        while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
        while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return f * x;
    }
    
    const int INF = 0x3f3f3f3f, N = 303, M = N << 1, mod = 1000000007;
    
    int n, m, t;
    LL d[N][N], a[N][N], l[N][N];
    
    inline LL solve()
    {
    	LL ans = 1, op = 1;
    	for (int i = 2; i <= n; i+=1)
    	{
    		for (int j = i + 1; j <= n; j+=1)
    		{
    			while (l[i][i])
    			{
    				int p = l[j][i] / l[i][i];
    				for (int k = i; k <= n; k+=1)
    				{
    					l[j][k] = ((l[j][k] - 1ll * p * l[i][k] % mod) % mod + mod) % mod;
    					swap(l[i][k], l[j][k]);
    				}
    				op *= -1;
    			}
    			swap(l[i], l[j]);
    			op *= -1;
    		}
    		ans = ans * l[i][i] % mod;
    	}
    	return (ans * op % mod + mod) % mod;
    }
    
    int main()
    {
        //File("");
        n = gi <int> (), m = gi <int> (), t = gi <int> ();
        for (int i = 1; i <= m; i+=1)
        {
        	int u = gi <int> (), v = gi <int> (), w = gi <int> ();
        	if (!t)
        	{
        		(d[u][u] += w) %= mod, (d[v][v] += w) %= mod;
        		(a[u][v] += w) %= mod, (a[v][u] += w) %= mod;
        	}
        	else
        	{
        		(d[v][v] += w) %= mod;
        		(a[u][v] += w) %= mod;
        	}
        }
        for (int i = 1; i <= n; i+=1)
        	for (int j = 1; j <= n; j+=1)
        		l[i][j] = d[i][j] - a[i][j];
        printf("%lld
    ", solve());
        return 0;
    }
    

    参考学习

    https://www.cnblogs.com/zj75211/p/8039443.html

    https://www.luogu.com.cn/blog/command-block/ju-zhen-shu-ding-li-xing-lie-shi-post

    http://oi-wiki.com/graph/matrix-tree/

  • 相关阅读:
    Bootstrap(2)整体架构
    介绍 Microservice
    Websocket实例
    MYSQL-用户权限的验证过程(转)
    don't touch your phone in any unfamiliar way(转)
    你真的会玩SQL吗?Case的用法(转)
    android模拟器与PC的端口映射(转)
    Java Main如何被执行?(转)
    Linux crontab 命令格式与具体样例
    分享一个3D球面标签云
  • 原文地址:https://www.cnblogs.com/xsl19/p/14423330.html
Copyright © 2011-2022 走看看