期望dp
第一次做这种题,搜了好多相关的资料才看懂。
规律
1.期望可以分解成多个子期望的加权和,权为子期望发生的概率,即
E
(
a
A
+
b
B
+
…
)
E ( a A + b B + … )
E(aA+bB+…)
=
a
E
(
A
)
+
b
E
(
B
)
+
…
+
1
E
(
a
A
+
b
B
+
…
)
=a E ( A ) + b E ( B ) + … + 1 E(aA+bB+…)
=aE(A)+bE(B)+…+1E(aA+bB+…)
=
a
E
(
A
)
+
b
E
(
B
)
+
…
+
1
E
(
a
A
+
b
B
+
…
)
= aE(A) + bE(B) +…+1E(aA+bB+…)
=aE(A)+bE(B)+…+1E(aA+bB+…)
=
a
E
(
A
)
+
b
E
(
B
)
+
…
+
1
;
=aE(A)+bE(B)+…+1;
=aE(A)+bE(B)+…+1;
2.期望从后往前找,一般
d
p
[
n
]
=
0
,
d
p
[
0
]
dp[n]=0,dp[0]
dp[n]=0,dp[0] 是答案;
3.解决过程,找出各种情况乘上这种情况发生的概率,求和;
4.概率DP一定要初始化!
5.与常规的求解不同,数学期望经常逆向推出。
几种常见设转移方程数组的方法
设
f
[
i
]
f[ i ]
f[i] 表示的是由
i
i
i 状态变成 最终 状态的期望
按照题意直接设
把选择的东西加入数组,如
f
[
i
]
[
j
]
f[i][j]
f[i][j] 表示第
i
i
i 个物品选
j
j
j 个的期望或
f
[
i
]
[
j
]
f[i][j]
f[i][j] 表示有
i
i
i 个
A
A
A 物品,
j
j
j 个
B
B
B 物品的期望
code:
#include <bits/stdc++.h>
using namespace std;
#define maxn 305
double f[maxn][maxn][maxn];//状态:f[i,j,k]:有i个一个寿司盘子,j个两个寿司盘子,k个三个寿司盘子的期望值。
int a[5];
int n;
int main() {
scanf( "%d", &n );
for ( int i = 1, x; i <= n; i ++ ) scanf( "%d", &x ), a[x] ++; //统计各种寿司盘有多少
for ( int k = 0; k <= n; k ++ )
for ( int j = 0; j <= n; j ++ )
for ( int i = 0; i <= n; i ++ )
if ( i or j or k ) {//数学期望 P=Σ每一种状态*对应的概率,没啥可说的。
if ( i ) f[i][j][k] += f[i - 1][j][k] * i / (i + j + k); //个数为1的盘子吃掉一个就没有了;
if ( j ) f[i][j][k] += f[i + 1][j - 1][k] * j / (i + j + k); //个数为2的盘子吃掉一个就少了一个个数为2的盘子,多一个个数为1的盘子;
if ( k ) f[i][j][k] += f[i][j + 1][k - 1] * k / (i + j + k); //个数为3的盘子吃掉一个就少了一个个数为3的盘子,多一个个数为2的盘子
f[i][j][k] += n * 1.0 / (i + j + k);
}
printf( "%.10f\n", f[a[1]][a[2]][a[3]] );
}
还行,这个可以算个模板题了吧