期望 DP
期望
定义
略
性质
C C C 为常数, X , Y X,Y X,Y 为随机变量
- E ( C ) = C E(C)=C E(C)=C
- E ( C x ) = C E ( x ) E(Cx)=CE(x) E(Cx)=CE(x)
- E ( x + y ) = E ( x ) + E ( y ) E(x+y)=E(x)+E(y) E(x+y)=E(x)+E(y)
- 当 x , y x,y x,y 相互独立时, E ( x y ) = E ( x ) E ( y ) E(xy)=E(x)E(y) E(xy)=E(x)E(y)
注:3,4 条是重点
期望 DP
期望 DP,是一种 DP,所以核心思想与一般的 DP 差不多(事实上,并没有什么特别的)。
一般,设
f
[
i
]
[
j
]
f[i][j]
f[i][j] 为此状态的期望,状态转移时,将上一个状态的值和花费的和乘以转移的概率求和。(如成环,高斯消元)
例题
路径长度
题目描述
给定一起点为 1 1 1,终点为 n n n 的有向无环图,对于一个出度为 K K K 的点,走每条边离开的概率为 1 K \cfrac{1}{K} K1。求从起点到终点的路径期望长度。
这是一个引入。
利用性质 3,问题转化为求出经过每条边的期望次数,不过这并不好求,所以我们再转化为求每个节点的期望经过次数(这是一种十分常见的操作)。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
struct node {
int to, next, w;
} edge[200005];
int t[100005], cnt = 1, out[100005], in[100005];
int q[200005];
double ans, f[100005];
int n, m;
void create(int u, int v, int w) {
edge[cnt].next = t[u];
edge[cnt].to = v;
edge[cnt].w = w;
t[u] = cnt++;
out[u]++;
}
void solve() {
int l = 0, r = -1;
q[++r] = 1;
f[1] = 1;
while (l <= r) {
int _ = q[l++];
for (int i = t[_]; i; i = edge[i].next) {
int __ = edge[i].to;
f[__] += f[_] / out[_];
ans += f[_] * edge[i].w / out[_];
if (--in[__] == 0)
q[++r] = __;
}
}
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
create(u, v, w);
in[v]++;
}
solve();
printf("%.2f\n", ans);
return 0;
}
乘坐电梯
题目描述
n n n 个人排成一列,每秒钟队首的人有 p p p 的概率走上电梯,或 1 − p 1-p 1−p 的概率不动。求 T T T 秒后,电梯上人数的期望。
这就是一道十分模版的题了
设:
d
p
(
i
,
j
)
dp(i,j)
dp(i,j) 为第
i
i
i 秒电梯上有
j
j
j 个人的概率。决策是:上和不上。所以就有:
d
p
(
i
,
j
)
⋅
p
→
d
p
(
i
+
1
,
j
+
1
)
d
p
(
i
,
j
)
⋅
(
1
−
p
)
→
d
p
(
i
+
1
,
j
)
dp(i,j)\cdot p\to dp(i+1,j+1)\\ dp(i,j)\cdot (1-p)\to dp(i+1,j)
dp(i,j)⋅p→dp(i+1,j+1)dp(i,j)⋅(1−p)→dp(i+1,j)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
double p, dp[2005][2005];
int n, t;
int main() {
scanf("%d%lf%d", &n, &p, &t);
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
double p0 = 1 - p;
for (int i = 0; i < t; i++) {
dp[i + 1][n] += dp[i][n];
for (int j = 0; j < n; j++)
if (dp[i][j] > 0)
dp[i + 1][j + 1] += dp[i][j] * p, dp[i + 1][j] += dp[i][j] * p0;
}
double ans = 0;
for (int i = 0; i <= n; i++) {
ans += dp[t][i] * i;
}
printf("%.6f\n", ans);
return 0;
}
期望收益
题目描述
给定一个序列,一些位置未被确定,是
o
o
o 或
x
x
x 的概率各
50
%
50\%
50%,对于一个
o
x
ox
ox(公牛)序列,连续的
a
a
a 长度的
o
o
o 可得到
a
2
a^2
a2 的收益,求期望收益。
第 3 条性质只适用于一次,所以我们要尝试把二次变成一次。
(
x
+
1
)
2
−
x
2
=
2
x
+
1
(x+1)^2-x^2=2x+1
(x+1)2−x2=2x+1,那么只需要两个量:至某一位置之前的
a
a
a 的期望,和期望收益。每次用期望长度乘 2 加 1,再乘上概率,就是增加的收益。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
double dp[300005], l[300005];
string s;
int n;
int main() {
cin >> n;
cin >> s;
int len = s.size();
for (int i = 1; i <= len; i++) {
if (s[i - 1] == 'x') {
dp[i] = dp[i - 1];
l[i] = 0;
continue;
}
if (s[i - 1] == 'o') {
dp[i] = 2 * l[i - 1] + 1 + dp[i - 1];
l[i] = l[i - 1] + 1;
continue;
}
dp[i] = dp[i - 1] + l[i - 1] + 0.5;
l[i] = (l[i - 1] + 1) / 2;
}
printf("%.4f", dp[len]);
return 0;
}
期望分数
题目描述
还是 o x ox ox 序列,每个位置为 o o o 的概率为 p p p, x x x 为 ( 1 − p ) (1-p) (1−p),连续的 a a a 长度的 o o o 可得到 a 3 a^3 a3 的收益,求期望收益。
和上一题挺像,但又高了一次,还多了个概率。
k
1
=
(
x
+
1
)
3
−
x
3
=
3
x
2
+
3
x
+
1
k_1=(x+1)^3-x^3=3x^2+3x+1
k1=(x+1)3−x3=3x2+3x+1
k
2
=
(
x
+
1
)
2
−
x
2
=
2
x
+
1
k_2=(x+1)^2-x^2=2x+1
k2=(x+1)2−x2=2x+1
先求
k
2
k_2
k2,再把
k
2
k_2
k2 带入
k
1
k_1
k1。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
double dp, l, d;
int n;
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
double p;
cin >> p;
dp += (d + 3 * l + 1) * p;
d = (d + l * 6 + 3) * p;
l = (l + 1) * p;
}
printf("%.1f", dp);
return 0;
}
习题
我们地方的荷花又在这陌生的水上开了花,放出同样的清香,只是名字换了。——泰戈尔
其实DP就像荷花,无论如何变化,其核心是相通的。

这篇博客介绍了期望DP的概念和性质,包括定义和常见的性质。通过解析几个例题,如路径长度、乘坐电梯、期望收益和期望分数,阐述了如何应用期望DP解决问题。博主强调在解决期望DP问题时,通常需要转化问题并利用概率和期望的性质进行状态转移。最后,博客还给出了相关习题以供读者练习。

1386

被折叠的 条评论
为什么被折叠?



