生成树

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了生成树相关的知识,希望对你有一定的参考价值。

[BZOJ 3534] 重建

  题意

  给定一张 n (1 < n <= 50) 个点 m 条边的无向图, 每条边有一定出现的概率, 问出现的边恰好形成一个生成树的概率.

  实现

  注意到对于出现概率为 1 的边, 分母可能为 0 . 我们对 d = 1 变换为 d = 1-EPS 就好了.

技术分享
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cctype>
 5 #include <cmath>
 6 #include <algorithm>
 7 using namespace std;
 8 #define F(i, a, b) for (register int i = (a); i <= (b); i++)
 9 #define db double
10 
11 const db EPS = 1e-9;
12 inline int sign(db x) { return fabs(x)<EPS ? 0 : x<0 ? -1 : 1; }
13 inline int cmp(db x, db y) { return sign(x-y); }
14 
15 const int N = 55;
16 
17 int n; db f[N][N], Div = 1;
18 inline void Init(int x, int y, db w) {
19     f[x][x] += w, f[y][y] += w, f[x][y] -= w, f[y][x] -= w;
20 }
21 db Det(void) {
22     n--;
23     db Ret = 1;
24     F(i, 1, n) {
25         int id = i;
26         while (sign(f[id][i]) == 0) id++;
27         if (id > n) return 0;
28         if (id != i) {
29             F(k, 1, n) swap(f[i][k], f[id][k]);
30             Ret = -Ret;
31         }
32         Ret *= f[i][i];
33         F(j, i+1, n) if (sign(f[j][i]) != 0) {
34             db t = f[j][i] / f[i][i];
35             F(k, i, n) f[j][k] -= t * f[i][k];
36         }
37     }
38     return Ret;
39 }
40 
41 int main(void) {
42     #ifndef ONLINE_JUDGE
43         freopen("bzoj3534.in", "r", stdin);
44     #endif
45     
46     scanf("%d", &n);
47     F(i, 1, n) F(j, 1, n) {
48         db p; scanf("%lf", &p);
49         if (i < j) {
50             if (cmp(p, 1) == 0) p -= EPS;
51             Div *= 1-p;
52             Init(i, j, p/(1-p));
53         }
54     }
55     printf("%0.8lf\n", Div * Det());
56     
57     return 0;
58 }
View Code

 

 

 

[BZOJ 1016] 最小生成树计数

  题意

  给定一张 n (n <= 16) 个点的图, 求有多少棵最小生成树.

  分析

  Kruskal 算法告诉我们, 每种边使用的数量相同, 它们构成的连通性相同.

  在 Kruskal 的同时, 该权值作用之前的连通块当做若干个点, 它们在该权值作用之后形成若干个连通块, 对每个连通块进行生成树计数.

  实现

  使用 vector 进行分类重标号.

  

 

 

Mashmokh‘s Designed Problem  01生成树

  题意

  给一张 n (1 <= n <= 100000) 个点 m (1 <= m <= 100000) 条边的无向连通图, 每条边的权值可能为 0 或 1 , 问是否存在一种生成树权值为 x ?

  分析

  考虑构建最小生成树, 最大生成树, 最小生成树的权值为 Min, 最大生成树的权值为 Max , 显然能构造出来的权值只可能在 [Min, Max] 之间.

  最小生成树一定可以通过若干次消圈得到最大生成树, 而边权又是 0 或 1, 所以变化是连续的, 所以 [Min, Max] 之间的所有权值都可以构造出来.

  综上, 存在一种生成树权值为 x 当且仅当 Min <= x 且 x <= Max .

 

 

 

[Hdu 5304]  基环树计数

  题意  

  给定一张 n 个点 m 条边的无向图, 问其有多少个基环生成树.

  n <= 16 , 无重边, 无自环.

  分析

  利用状压DP 求每种环的状态的个数.

  枚举环, 缩点, 利用 Matrix-Tree定理 进行计数.

  实现

  f[s][i] 表示从 s 状态中的最小值出发, 终点在 i 的方案数.

  边界 f[2 ^ i][i] = 1 .

  统计答案的时候, 对于 f[s][i] , 若 s 中的个数大于 2 , 且 i 能到达 s 状态中的最小值, 则 cnt[s] += f[s][i] .

技术分享
  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <cctype>
  5 #include <algorithm>
  6 using namespace std;
  7 #define F(i, a, b) for (register int i = (a); i <= (b); i++)
  8 #define D(i, a, b) for (register int i = (a); i >= (b); i--)
  9 inline int rd(void) {
 10     int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == -) f = -1;
 11     int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-0; return x*f;
 12 }
 13 
 14 const int N = 20;
 15 const int S = 70000;
 16 const int MOD = 998244353;
 17 
 18 inline void Add(int &x, int y) { x = (x + y) % MOD; }
 19 inline int Pow(int x, int y) {
 20     int Mul = 1;
 21     for (; y > 0; y >>= 1, x = 1LL * x * x % MOD)
 22         if (y & 1) Mul = 1LL * Mul * x % MOD;
 23     return Mul;
 24 }
 25 inline int Inv(int x) { return Pow(x, MOD-2); }
 26 
 27 int n, m; bool G[N][N];
 28 int Full, cnt[S], f[S][N];
 29 int Lab[N], tot, Mat[N][N], ans;
 30 
 31 void Build(int s) {
 32     tot = 1; F(i, 1, n) Lab[i] = (s >> i-1 & 1 ? 1 : ++tot);
 33     memset(Mat, 0, sizeof Mat);
 34     F(i, 1, n) F(j, i+1, n)
 35         if (G[i][j] && Lab[i] != Lab[j]) {
 36             Mat[Lab[i]][Lab[i]]++, Mat[Lab[j]][Lab[j]]++;
 37             Mat[Lab[i]][Lab[j]]--, Mat[Lab[j]][Lab[i]]--;
 38         }
 39 }
 40 int Gauss(void) {
 41     tot--;
 42     int Mul = 1;
 43     F(i, 1, tot) {
 44         if (!Mat[i][i]) {
 45             F(j, i+1, tot) if (Mat[j][i] != 0) {
 46                 F(k, 1, tot) swap(Mat[i][k], Mat[j][k]);
 47                 Mul = -Mul;
 48                 break;
 49             }
 50         }
 51         if (!Mat[i][i]) return 0;
 52         Mul = 1LL * Mul * Mat[i][i] % MOD;
 53         int I = Inv(Mat[i][i]);
 54         F(j, i+1, tot) if (Mat[j][i] != 0) {
 55             int t = 1LL * I * Mat[j][i] % MOD;
 56             F(k, i, tot)
 57                 Add(Mat[j][k], -1LL * Mat[i][k] * t % MOD);
 58         }
 59     }
 60     return Mul;
 61 }
 62 
 63 int main(void) {
 64     #ifndef ONLINE_JUDGE
 65         freopen("hdu5304.in", "r", stdin);
 66     #endif
 67     
 68     int inv2 = Inv(2);
 69     while (~scanf("%d %d", &n, &m)) {
 70         memset(G, false, sizeof G);
 71         F(i, 1, m) {
 72             int x = rd(), y = rd();
 73             G[x][y] = G[y][x] = true;
 74         }
 75         
 76         Full = (1 << n) - 1, memset(cnt, 0, sizeof cnt), memset(f, 0, sizeof f);
 77         F(i, 1, n) f[1 << i-1][i] = 1;
 78         F(s, 1, Full) {
 79             int Min = 0; D(i, n, 1) if (s >> i-1 & 1) Min = i;
 80             F(i, Min, n) if ((s >> i-1 & 1) && f[s][i] != 0) {
 81                 F(j, Min+1, n) if (!(s >> j-1 & 1) && G[i][j])
 82                     Add(f[s | 1 << j-1][j], f[s][i]);
 83             }
 84         }
 85         F(s, 1, Full) {
 86             int tot = 0; for (int x = s; x > 0 && tot <= 2; x ^= (x & -x), tot++); if (tot <= 2) continue;
 87             int Min = 0; D(i, n, 1) if (s >> i-1 & 1) Min = i;
 88             F(i, Min+1, n) if ((s >> i-1 & 1) && G[i][Min])
 89                 Add(cnt[s], f[s][i]);
 90             cnt[s] = 1LL * cnt[s] * inv2 % MOD;
 91         }
 92         
 93         ans = 0;
 94         F(s, 1, Full) if (cnt[s] != 0) {
 95             Build(s);
 96             Add(ans, 1LL * cnt[s] * Gauss() % MOD);
 97         }
 98         printf("%d\n", (ans + MOD) % MOD);
 99     }
100     
101     return 0;
102 }
View Code

 

以上是关于生成树的主要内容,如果未能解决你的问题,请参考以下文章

Apollo Codegen 没有找到生成代码的操作或片段

前端开发工具vscode如何快速生成代码片段

前端开发工具vscode如何快速生成代码片段

vscode代码片段生成vue模板

机器学习——模型树

VS Code配置snippets代码片段快速生成html模板,提高前端编写效率