题解:P9428 [蓝桥杯 2023 国 B] 逃跑

节选自:DP做题记录(三)(2025.4.5 - 2025.4.19)

这道题代码难度只有红,但思维难度直接把这道题提升到了绿。

我们设 \(dp_i\) 表示从第 \(i\) 个星球出发到根节点花费的最短时间的期望。

显然,如果一个星球 \(v\) 的父亲节点 \(u\) 是跳板星球,那么直接跳跃与往上走父亲是一样的效果,因此 \(dp_v = dp_u + 1\)

那么如果 \(v\) 的父亲节点 \(u\) 不是跳板星球,那么此时直接跳跃肯定要更优秀一些。假设我们有至少一次跳成功了,那么这种情况的时间一定在 \(u\) 已经考虑过了(如果 \(v\) 跳成功,就钦定 \(u\) 这次一定跳成功;如果 \(v\) 失败了,就钦定 \(u\) 这次也失败了,这样一定能保证 \(u\)\(v\) 到达根的时间一样)。唯一一种 \(u\) 无法复制的情况就是 \(v\) 每次跳跃都失败了,此时它就会多走一条 \(v\)\(u\) 的边,概率是 \(p^{cnt}\)\(cnt\)\(v\) 到根路径上跳板星球的数量),因此对答案的贡献就会家上 \(p^{cnt}\),因此 \(dp_v = dp_u + p^{cnt}\),那么这道题就做完了。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 9;
struct Edge{
	int v, nex;
} e[N << 1], e2[N];
int head[N], ecnt;
void addEdge(int u, int v){
	e[++ecnt] = Edge{v, head[u]};
	head[u] = ecnt;
}
int flag[N], n, m;
double dp[N], p, ans;
void dfs(int u, int fa, double pp){
	if(flag[fa])
		pp *= p;
	if(u != 1){
		if(flag[fa])
			dp[u] = dp[fa] + 1;
		else
			dp[u] = dp[fa] + pp;
	}
	ans += dp[u];
	for(int i = head[u]; i; i = e[i].nex){
		int v = e[i].v;
		if(v == fa)
			continue;
		dfs(v, u, pp);
	}
	pp /= p;
}
int main(){
	scanf("%d%d%lf", &n, &m, &p);
	for(int i = 1; i < n; i++){
		int u, v;
		scanf("%d%d", &u, &v);
		addEdge(u, v);
		addEdge(v, u);
	}
	for(int i = 1; i <= m; i++){
		int u;
		scanf("%d", &u);
		flag[u] = true;
	}
	dfs(1, 0, 1);
	printf("%.2lf", ans / n);
	return 0;
}
posted @ 2025-04-22 17:10  Orange_new  阅读(36)  评论(0)    收藏  举报