期望dp自学笔记

期望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]] );
}

还行,这个可以算个模板题了吧

猜你喜欢

转载自blog.csdn.net/skyflying266/article/details/125369077