zoukankan      html  css  js  c++  java
  • 矩阵树定理学习笔记

    这也是一个黑科技

    设一个无向图的邻接矩阵为$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 }

  • 相关阅读:
    html控件使用
    托盤
    托盘的实现
    ws2s函数
    网络验证
    右上角X灰化
    如何模拟一个http请求并把response的内容保存下载下来,导出到excel中(结尾福利)
    排序的几种算法(一):冒泡排序
    python中的break eturnpasscontinue用法
    python中socket模块详解
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/10464629.html
Copyright © 2011-2022 走看看