「CF 123E」Maze
题意澄清
对于 dfs 遍历时,在某一个点进入子树的顺序并不是按输入顺序,而是假定随机选择未进入过的子树 (这纠结了我好久) 。
破题思路
首先可以明确这题不能推一个
其次,考虑到需要对于每一个点作起点求出期望步数,又是一棵树,故树形
那么算法分析完了(树形
以子树根作起点的期望步数
对于每一棵子树,假设其根为
其中
树形dp
对于第一次树形
先明确一下定义。
首先我们先处理式子中的
- 终点不在
的子树中
概率为
贡献为
影响为 - 终点在
的子树中
概率为
贡献为
影响为
故
接下来我们处理以
- 终点在原本
的子树中
概率为
贡献为
期望步数为 - 终点不在原本
的子树中
模仿原 式子可得
故
实现
综合上述内容,便有了以下代码。
/*
address:https://codeforces.com/problemset/problem/123/E
AC 2024/8/28 12:26
*/
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
vector<int>G[N];
int n;
double p1[N], p2[N];
int sum1, sum2;
double f[N], g[N], sum_p[N];
int siz[N];
inline void dfs1(int u, int fa) {
sum_p[u] = p2[u];
siz[u] = 1;
for (auto v : G[u]) {
if (v == fa) continue;
dfs1(v, u);
sum_p[u] += sum_p[v];
siz[u] += siz[v];
}
for (auto v : G[u]) {
if (v == fa) continue;
g[u] += (siz[u] - siz[v]) * sum_p[v] + g[v];
}
}
inline void dfs2(int u, int fa) {
for (auto v : G[u]) {
if (v == fa) continue;
double except_v = f[u] - siz[v] * (1 - p2[u] - sum_p[v]) - (n - siz[v]) * sum_p[v];
f[v] = (n - siz[v]) * (sum_p[v] - p2[v]) + (n - (n - siz[v])) * (1 - sum_p[v]) + except_v;
dfs2(v, u);
}
}
int main() {
scanf("%d", &n);
for (int i = 1;i < n;i++) {
int u, v;scanf("%d%d", &u, &v);
G[u].push_back(v);G[v].push_back(u);
}
for (int i = 1;i <= n;i++) scanf("%lf%lf", &p1[i], &p2[i]), sum1 += p1[i], sum2 += p2[i];
for (int i = 1;i <= n;i++) p1[i] /= sum1, p2[i] /= sum2;
dfs1(1, 0);
f[1] = g[1];
dfs2(1, 0);
double ans = 0;
for (int i = 1;i <= n;i++) ans += p1[i] * f[i];
printf("%.12lf", ans);
return 0;
}
The end
一道概率期望加树形
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现