日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

矩阵树定理学习笔记

發布時間:2025/7/14 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 矩阵树定理学习笔记 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

這也是一個黑科技

設一個無向圖的鄰接矩陣為$A$,度數矩陣為$D$,則基爾霍夫矩陣$K=D-A$的行列式的值就是生成樹的個數。

注意這里的$K$是要把最后一行和最后一列去掉的。

(證明?不存在的)

它還有一個擴展,叫做變元矩陣樹定理

若將鄰接矩陣的$A[i][j]$設為邊權,度數矩陣的$D[i][i]$設為與$i$相連的邊權的和,則這個值就是所有生成樹邊權之積的和。


P4111 [HEOI2015]小Z的房間

這道題就是模板題,直接套定理就行。

1 #include<cstdio> 2 #include<algorithm> 3 #define Rint register int 4 using namespace std; 5 typedef long long LL; 6 const int N = 11, mod = 1e9; 7 int n, m, id[N][N], tot, f[N * N][N * N]; 8 char str[N][N]; 9 inline void add(int a, int b){ 10 ++ f[a][a]; ++ f[b][b]; 11 -- f[a][b]; -- f[b][a]; 12 } 13 inline int Gauss(){ 14 int res = 1; 15 for(Rint i = 1;i < tot;i ++){ 16 for(Rint j = i + 1;j < tot;j ++) 17 while(f[j][i]){ 18 int t = f[i][i] / f[j][i]; 19 for(Rint k = i;k < tot;k ++) 20 f[i][k] = (f[i][k] - (LL) t * f[j][k] + mod) % mod; 21 swap(f[i], f[j]); 22 res = -res; 23 } 24 res = (LL) res * f[i][i] % mod; 25 res = (res + mod) % mod; 26 } 27 return (res + mod) % mod; 28 } 29 int main(){ 30 scanf("%d%d", &n, &m); 31 for(Rint i = 1;i <= n;i ++){ 32 scanf("%s", str[i] + 1); 33 for(Rint j = 1;j <= m;j ++) if(str[i][j] == '.') id[i][j] = ++ tot; 34 } 35 for(Rint i = 1;i <= tot;i ++) 36 for(Rint j = 1;j <= tot;j ++) f[i][j] = (f[i][j] + mod) % mod; 37 for(Rint i = 1;i <= n;i ++) 38 for(Rint j = 1;j <= m;j ++) 39 if(str[i][j] == '.'){ 40 if(str[i][j - 1] == '.') add(id[i][j], id[i][j - 1]); 41 if(str[i - 1][j] == '.') add(id[i][j], id[i - 1][j]); 42 } 43 printf("%d", Gauss()); 44 }

P4336 [SHOI2016]黑暗前的幻想鄉

這道題就是要套一個容斥原理。

都要選=可以都選-一個不選+二個不選-三個不選...

然后枚舉子集,重構一下矩陣就可以過了。

時間復雜度$O(2^nn^3)$

1 #include<cstdio> 2 #include<vector> 3 #include<cstring> 4 #define Rint register int 5 using namespace std; 6 typedef long long LL; 7 typedef pair<int, int> pii; 8 const int mod = 1e9 + 7; 9 int n, f[18][18], ans, pre[1 << 16]; 10 vector<pii> g[18]; 11 inline void add(int a, int b){ 12 ++ f[a][a]; ++ f[b][b]; 13 -- f[a][b]; -- f[b][a]; 14 } 15 inline int Gauss(){ 16 int res = 1; 17 for(Rint i = 1;i < n;i ++){ 18 for(Rint j = i + 1;j < n;j ++) 19 while(f[j][i]){ 20 int d = f[i][i] / f[j][i]; 21 for(Rint k = i;k < n;k ++) f[i][k] = (f[i][k] - (LL) d * f[j][k] + mod) % mod; 22 swap(f[i], f[j]); 23 res = -res; 24 } 25 res = (LL) res * f[i][i] % mod; 26 } 27 return (res + mod) % mod; 28 } 29 int main(){ 30 scanf("%d", &n); 31 for(Rint i = 1;i < n;i ++){ 32 int m; 33 scanf("%d", &m); 34 while(m --){ 35 int x, y; 36 scanf("%d%d", &x, &y); 37 g[i].push_back(make_pair(x, y)); 38 } 39 } 40 for(Rint i = 1;i < (1 << n - 1);i ++) pre[i] = pre[i >> 1] + (i & 1); 41 for(Rint i = 1;i < (1 << n - 1);i ++){ 42 memset(f, 0, sizeof f); 43 for(Rint j = 1;j < n;j ++) 44 if(i & (1 << j - 1)) 45 for(Rint k = 0;k < g[j].size();k ++) 46 add(g[j][k].first, g[j][k].second); 47 for(Rint j = 1;j < n;j ++) 48 for(Rint k = 1;k < n;k ++) 49 f[j][k] = (f[j][k] + mod) % mod; 50 if((n - pre[i]) & 1) ans = (ans + Gauss()) % mod; 51 else ans = (ans + mod - Gauss()) % mod; 52 } 53 printf("%d\n", ans); 54 }

P3317 [SDOI2014]重建

這道題就要稍微推一下柿子了

$$\sum_{Tree}\prod_{(u,v)\in Tree}P_{u,v}*\prod_{(u,v)\in Tree}(1-P_{u,v})$$

$$=\prod_{(u,v)}(1-P_{u,v})*\sum_{Tree}\prod_{(u,v)\in Tree}\frac{P_{u,v}}{1-P_{u,v}}$$

前一部分預處理,后一部分直接算。

1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 #define Rint register int 5 using namespace std; 6 const int N = 51; 7 const double eps = 1e-8; 8 int n; 9 double p[N][N], f[N][N], ans = 1; 10 inline void add(int a, int b, double c){ 11 f[a][a] += c; f[b][b] += c; 12 f[a][b] -= c; f[b][a] -= c; 13 } 14 inline double Gauss(){ 15 double res = 1; 16 for(Rint i = 1;i < n;i ++){ 17 for(Rint j = i + 1;j < n;j ++){ 18 int t = i; 19 if(fabs(f[j][i]) > fabs(f[t][i])) t = j; 20 if(t != i) swap(f[i], f[t]), res = -res; 21 } 22 for(Rint j = i + 1;j < n;j ++){ 23 double t = f[j][i] / f[i][i]; 24 for(Rint k = i;k < n;k ++) f[j][k] -= f[i][k] * t; 25 } 26 res *= f[i][i]; 27 } 28 return res; 29 } 30 int main(){ 31 scanf("%d", &n); 32 for(Rint i = 1;i <= n;i ++) 33 for(Rint j = 1;j <= n;j ++){ 34 scanf("%lf", p[i] + j); 35 if(i < j){ 36 if(fabs(p[i][j]) < eps) p[i][j] = eps; 37 else if(fabs(1 - p[i][j]) < eps) p[i][j] = 1 - eps; 38 ans *= 1 - p[i][j]; 39 add(i, j, p[i][j] / (1 - p[i][j])); 40 } 41 } 42 printf("%.6lf", ans * Gauss()); 43 }

P4208 [JSOI2008]最小生成樹計數

【TODO】

轉載于:https://www.cnblogs.com/AThousandMoons/p/10464629.html

總結

以上是生活随笔為你收集整理的矩阵树定理学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。