矩阵树定理
显然只需要这个
矩阵行列式
定义矩阵的行列式 , 为一个排列
交换矩阵两行行列式变为相反数,一行加减另一行若干倍行列式不变
求行列式的方法:高斯消元消成上三角然后对角线乘积即为行列式
若模数不为质数,则辗转相除消元
矩阵树定理
定义: 为图的邻接矩阵
无向图: 为图的度数矩阵
有向图: 为图的入度矩阵, 为图的出度矩阵
注:若边带权,把它当做权值条边即可
生成树权值和计数(权值为树边乘积):
以 为根,去掉基尔霍夫矩阵第 行和第 列后的行列式即为答案
无向图删谁都可以,答案是一样的
基尔霍夫矩阵
无向图:
有向图外向树:
有向图内向树:
#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)); }
#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 定理
有向欧拉图本质不同的欧拉回路数量为:
为内向生成树数量
【模板】BEST 定理
这题答案为未去掉循环同构的欧拉回路,所以最后要乘上
#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); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具