1 条题解
-
0
题目描述
有一棵以 为根的有根树,包含 个节点。游戏过程如下:
- 每一步,从当前剩余的节点中均匀随机选择一个节点 。
- 删除以 为根的整个子树(包括 本身)。
- 游戏在删除根节点 后结束(此时树为空)。
求游戏步数的期望值。
解法分析
关键转化
考虑任意一个节点 。它会在什么情况下作为一次“被选中的节点”而贡献一步?
- 如果 的某个祖先 ()在 之前被选中,那么 将在 被选中的那一步中被连带删除,不会单独被选中。
- 只有当从根到 的路径上的所有节点中, 是第一个被选中的节点时, 才会成为一次选中的节点,贡献 步。
因此,节点 对总步数的贡献是一个指示随机变量 , 当且仅当 是根到 路径上第一个被选中的节点。
概率计算
设 为节点 的深度(根深度为 )。根到 的路径上有 个节点。
由于每一步都是均匀随机地从剩余节点中选取,且删除操作不会改变路径上节点之间的相对顺序(它们互为祖先‑后代关系),可以证明:这 个节点在游戏中被选中的顺序是均匀随机的,所有 种排列等可能。
因此, 成为第一个被选中的概率为 。期望步数
由期望的线性性质:
$$E = \sum_{v=1}^{n} \Pr(\text{$v$ 被单独选中}) = \sum_{v=1}^{n} \frac{1}{d_v}. $$算法步骤
- 读入 和 条边,建树。
- 以 为根进行 DFS 或 BFS,计算每个节点的深度 (根深度为 )。
- 累加 ,输出结果。
时间复杂度 ,空间复杂度 。
标程
#include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n; cin >> n; vector<vector<int>> g(n + 1); for (int i = 1; i < n; ++i) { int a, b; cin >> a >> b; g[a].push_back(b); g[b].push_back(a); } vector<int> depth(n + 1, 0); function<void(int, int)> dfs = [&](int u, int p) { depth[u] = depth[p] + 1; // 根 depth[1] = 1 for (int v : g[u]) { if (v != p) dfs(v, u); } }; dfs(1, 0); double ans = 0.0; for (int i = 1; i <= n; ++i) { ans += 1.0 / depth[i]; } cout << fixed << setprecision(15) << ans << '\n'; return 0; }
- 1
信息
- ID
- 6201
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者