矩阵树定理

Conclusion

显然只需要这个

矩阵行列式

定义矩阵的行列式 det(A)=psgnai,pip 为一个排列
交换矩阵两行行列式变为相反数,一行加减另一行若干倍行列式不变
求行列式的方法:高斯消元消成上三角然后对角线乘积即为行列式
若模数不为质数,则辗转相除消元

矩阵树定理

定义:A 为图的邻接矩阵
无向图:D 为图的度数矩阵
有向图:Din 为图的入度矩阵,Dout 为图的出度矩阵
注:若边带权,把它当做权值条边即可

生成树权值和计数(权值为树边乘积):
i 为根,去掉基尔霍夫矩阵第 i 行和第 i 列后的行列式即为答案
无向图删谁都可以,答案是一样的

基尔霍夫矩阵 K
无向图:K=DA
有向图外向树:K=DinA
有向图内向树:K=DoutA

P6178 【模板】MatrixTree 定理

Code
#include <bits/stdc++.h>
#define IN inline
using namespace std;
typedef long long LL;
const int N = 305, P = 1e9 + 7;
int n, m, t, deg[N], adj[N][N], a[N][N];
IN void Add(int &x, int y){if ((x += y) >= P) x -= P;}
IN int fpow(int x, int y){int s = 1; for(; y; y >>= 1, x = (LL)x * x % P) if (y & 1) s = (LL)s * x % P; return s;}
IN int Det(int n) {
int fl = 1, res = 1;
for(int i = 1; i <= n; i++) {
int t = 0;
for(int j = i; j <= n; j++) if (a[j][i]) {t = j; break;}
if (!t) return 0;
if (t ^ i) {
for(int j = 1; j <= n; j++) swap(a[i][j], a[t][j]);
fl ^= 1;
}
int inv = fpow(a[i][i], P - 2);
for(int j = i + 1; j <= n; j++) {
t = (LL)a[j][i] * inv % P;
for(int k = i; k <= n; k++) a[j][k] = ((LL)a[j][k] - (LL)a[i][k] * t % P + P) % P;
}
res = (LL)res * a[i][i] % P;
}
return (fl ? P - res : res);
}
int main() {
scanf("%d%d%d", &n, &m, &t);
for(int i = 1, u, v, w; i <= m; i++) {
scanf("%d%d%d", &u, &v, &w);
Add(adj[v][u], w), Add(deg[v], w);
if (!t) Add(deg[u], w), Add(adj[u][v], w);
}
for(int i = 1; i <= n; i++) {
a[i][i] = deg[i];
for(int j = 1; j <= n; j++) a[i][j] = (a[i][j] - adj[i][j] + P) % P;
}
for(int i = 1; i <= n; i++) swap(a[1][i], a[n][i]);
printf("%d\n", Det(n - 1));
}

P4111 [HEOI2015] 小 Z 的房间

Code
#include <cstdio>
#include <iostream>
#define IN inline
using namespace std;
template <typename Tp>
IN void read(Tp &x) {
x = 0; char ch = getchar(); int f = 0;
for(; !isdigit(ch); f = (ch == '-' ? 1 : f), ch = getchar());
for(; isdigit(ch); x = (x<<3)+(x<<1)+(ch^48), ch = getchar());
if (f) x = ~x + 1;
}
typedef long long LL;
const int N = 105, P = 1e9;
int n, m, a[N][N], id[N][N];
char s[N][N];
IN void add(int x, int y){++a[x][x], ++a[y][y], --a[x][y], --a[y][x];}
int main() {
read(n), read(m);
int cnt = 0;
for(int i = 1; i <= n; i++) {
scanf("%s", s[i] + 1);
for(int j = 1; j <= m; j++) if (s[i][j] == '.') id[i][j] = ++cnt;
}
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++) if (s[i][j] == '.') {
if (j < m && s[i][j + 1] == '.') add(id[i][j], id[i][j + 1]);
if (i < n && s[i + 1][j] == '.') add(id[i][j], id[i + 1][j]);
}
--cnt;
int ans = 1;
for(int i = 1; i <= cnt; i++)
for(int j = i + 1; j <= cnt; j++)
while (a[j][i]) {
int p = a[i][i] / a[j][i];
for(int k = i; k <= cnt; k++) a[i][k] = (a[i][k] - (LL)a[j][k] * p % P + P) % P;
for(int k = i; k <= cnt; k++) swap(a[i][k], a[j][k]);
ans *= -1;
}
for(int i = 1; i <= cnt; i++) ans = ((LL)ans * a[i][i] % P + P) % P;
printf("%d\n", ans);
}

BEST 定理

有向欧拉图本质不同的欧拉回路数量为:T(outi1)!
T 为内向生成树数量

【模板】BEST 定理
这题答案为未去掉循环同构的欧拉回路,所以最后要乘上 out1

Code
#include <cstdio>
#include <iostream>
#include <cstring>
#define IN inline
using namespace std;
template <typename Tp>
IN void read(Tp &x) {
x = 0; char ch = getchar(); int f = 0;
for(; !isdigit(ch); f = (ch == '-' ? 1 : f), ch = getchar());
for(; isdigit(ch); x = (x<<3)+(x<<1)+(ch^48), ch = getchar());
if (f) x = ~x + 1;
}
typedef long long LL;
const int N = 105, P = 1e6 + 3;
int n, a[N][N], fa[N], out[N], in[N], fac[200005];
int find(int x){return x == fa[x] ? x : fa[x] = find(fa[x]);}
IN int Gauss() {
int m = n - 1, res = 1;
for(int i = 1; i <= m; i++)
for(int j = i + 1; j <= m; j++)
while (a[j][i]) {
int p = a[i][i] / a[j][i];
for(int k = i; k <= m; k++) a[i][k] = (a[i][k] - (LL)a[j][k] * p % P + P) % P;
for(int k = i; k <= m; k++) swap(a[i][k], a[j][k]);
res *= -1;
}
for(int i = 1; i <= m; i++) if (a[i][i]) res = ((LL)res * a[i][i] % P + P) % P;
return res;
}
int main() {
fac[0] = 1; for(int i = 1; i <= 200000; i++) fac[i] = (LL)fac[i - 1] * i % P;
int t; read(t);
for(; t; --t ) {
read(n), memset(a, 0, sizeof a), memset(in, 0, sizeof in);
for(int i = 1; i <= n; i++) fa[i] = i;
for(int i = 1, s; i <= n; i++) {
read(s), out[i] = a[i][i] = s;
for(int j = 1, x; j <= s; j++) read(x), --a[i][x], ++in[x], fa[find(i)] = find(x);
}
int flag = 0;
for(int i = 1; i <= n; i++) if (out[i] != in[i]) {flag = 1; break;}
for(int i = 1; i <= n; i++) if (find(i) != find(1) && out[i]) {flag = 1; break;}
if (flag) {puts("0"); continue;}
if (!out[1]) {puts("1"); continue;}
int ans = (LL)out[1] * Gauss() % P;
for(int i = 1; i <= n; i++) if (out[i]) ans = (LL)ans * (fac[out[i] - 1] + P) % P;
printf("%d\n", ans);
}
}
posted @   leiyuanze  阅读(45)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示