【数学】Matrix-Tree 定理
题目描述
给定一张
定义其一个生成树
求其所有不同生成树的权值之和,对
注意:
-
本题中,有向图的生成树指的是 以
为根的外向树; -
两棵生成树
不同,当且仅当存在存在一条边 ,满足 。
算法描述(暂缺证明)
考虑我们定义这张无向图的邻接矩阵
这张图的 基尔霍夫矩阵 为
那么这个基尔霍夫矩阵的一个
可以用于重边情况。
至于行列式,直接
#include<bits/stdc++.h>
using namespace std;
const int N = 305,MOD = 1e9 + 7;
typedef long long ll;
ll D[N][N],A[N][N],K[N][N];
int n,m,t;
inline ll ksm(ll base,int pts)
{
ll ret = 1;
for(;pts > 0;pts >>= 1,base = base * base % MOD)
if(pts & 1)
ret = ret * base % MOD;
return ret;
}
inline ll Gauss()
{
ll res = 1;
for(int i = 1;i <= n;i++)
{
int tmp = i;
for(;tmp <= n;tmp++) if(K[tmp][i]) break;
if(tmp > n) return 0;
swap(K[tmp],K[i]);
if(tmp != i) res = (MOD - res);
ll inv = ksm(K[i][i],MOD - 2);
res = res * K[i][i] % MOD;
for(int j = i + 1;j <= n;j++)
{
ll rate = K[j][i] * inv % MOD;
for(int k = 1;k <= n;k++) K[j][k] = (K[j][k] - (rate * K[i][k] % MOD) + MOD) % MOD;
}
}
return res;
}
int main()
{
cin>>n>>m>>t;
for(int i = 1,x,y,z;i <= m;i++)
{
cin>>x>>y>>z;
if(x == y) continue;
if(t == 0)
{
D[x][x] = (D[x][x] + z) % MOD; D[y][y] = (D[y][y] + z) % MOD;
A[x][y] = (A[x][y] + z) % MOD; A[y][x] = (A[y][x] + z) % MOD;
}
else
{
D[y][y] = (D[y][y] + z) % MOD; A[x][y] = (A[x][y] + z) % MOD;
}
}
for(int i = 1;i <= n;i++) for(int j = 1;j <= n;j++) K[i][j] = (D[i][j] - A[i][j] + MOD) % MOD;
n--;
for(int i = 1;i <= n;i++)
for(int j = 1;j <= n;j++)
K[i][j] = K[i + 1][j + 1];
ll ans = Gauss();
cout<<ans;
return 0;
}
拓展应用
1.有向图:
对于有向图,如果求外向树,就将度数矩阵改为入度,反之,内向树改为出度即可。
还有一个结论就是以
2.意义:
我们发现,重边可以通过直接在
事实上是可以的,也就是说,矩阵树其实算的是这样一个东西:
其中
例题:
P3317 [SDOI2014] 重建 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
这题要求
就是
将边权设为
#include<bits/stdc++.h>
using namespace std;
const int N = 55;
const double eps = 1e-7;
struct Matrix{
double a[N][N];
}D,A,K,P;
int n;
inline double getdet(Matrix x)
{
double ret = 1;
for(int i = 1;i <= n - 1;i++)
{
int tmp = i;
while(tmp <= n - 1 && fabs(x.a[tmp][i]) < eps) tmp++;
if(tmp == n) return 0;
if(tmp ^ i)
{
for(int j = 1;j <= n - 1;j++) swap(x.a[tmp][j],x.a[i][j]);
ret = -ret;
}
ret *= x.a[i][i];
for(int j = i + 1;j <= n - 1;j++)
{
double rate = x.a[j][i] / x.a[i][i];
for(int k = 1;k <= n - 1;k++) x.a[j][k] = x.a[j][k] - x.a[i][k] * rate;
}
}
return ret;
}
int main()
{
cin>>n;
for(int i = 1;i <= n;i++)
for(int j = 1;j <= n;j++)
cin>>A.a[i][j];
for(int i = 1;i <= n;i++)
for(int j = 1;j <= n;j++)
K.a[i][j] = D.a[i][j] = 0;
double prod = 1;
for(int i = 1;i <= n;i++)
for(int j = i + 1;j <= n;j++)
prod *= 1 + eps - A.a[i][j];
for(int i = 1;i <= n;i++)
for(int j = 1;j <= n;j++)
A.a[i][j] = A.a[i][j] / (1 + eps - A.a[i][j]);
for(int i = 1;i <= n;i++)
for(int j = i + 1;j <= n;j++)
D.a[i][i] += A.a[i][j],D.a[j][j] += A.a[i][j];
for(int i = 1;i <= n - 1;i++)
for(int j = 1;j <= n - 1;j++)
K.a[i][j] = D.a[i][j] - A.a[i][j];
cout<<fixed<<setprecision(15)<<prod * getdet(K);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话