概率dp入门 求期望

题意:

题目

有n类bug, s种系统,每个bug可以属于一种系统,一类bug。

每天可以找到一个新的bug,这个bug属于每一类bug的概率相同都是\frac{1}{n} ,属于每一种系统的概率也是相同的,都是\frac{1}{s}

那么要使得每一类bug都至少有一个bug,每一个系统也至少有一个bug,所需要的天数的期望是多少。

输入n和s输出天数的期望

思路:

考虑如果没有s种系统,只需要找到n类不同的bug,那么就非常的简单,这个期望就是n

对于概率dp都是倒着推导的,dp[i][j]代表已经找到了i类bug,j种系统,需要的期望。

很明显dp[n][s] = 0,对于dp[i][j]来说,下一个状态可能有四种情况。

1 找到的这个bug的类和系统都是以前出现过的,状态:dp[i][j] , 概率:i*j / (n*s)

2 这个bug的类没有出现过,系统出现过,状态:dp[i+1][j],概率:(n-i)*j / (n*s)

3  这个bug的类出现过,系统没有出现过,状态:dp[i][j+1] 概率  i * (s -j ) / (n*s)

4 这个bug的类个系统都没有出现过, 状态: dp[i+1][j+1] 概率: (n-i) * (s - j) / (n *s)

状态转移方程:dp[i][j] = dp[i][j] * (i*j / (n*s)) + dp[i+1][j] * ((n-i)*j / (n*s)) + dp[i][j+1] * ( i * (s -j ) / (n*s)) + dp[i+1][j+1] * ((n-i) * (s - j) / (n *s)) + 1

+1 是因为步数应该加一,因为多了一天了。

左右两边全部都乘上n*s。 dp[i][j] * n *s  = dp[i][j] * i *j + dp[i+1][j] *(n-i)*j + dp[i][j+1] * i * (s -j ) + dp[i+1][j+1] * (n-i ) * (s-j) + n *s 

合并dp[i][j]

dp[i][j] (n*s - i *j ) = dp[i+1][j] *(n-i)*j + dp[i][j+1] * i * (s -j ) + dp[i+1][j+1] * (n-i ) * (s-j) + n *s 

左右两边都除以(n * s - i * j ) 

dp[i][j] = (dp[i+1][j] *(n-i)*j + dp[i][j+1] * i * (s -j ) + dp[i+1][j+1] * (n-i ) * (s-j) + n *s ) / (n*s - i * j)

 

#pragma warning(disable:4996)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn = 505;
const ll mod = 10000;
double dp[1005][1005];
int main()
{
	int n, i, j, s;
	scanf("%d%d", &n, &s);
	memset(dp, 0, sizeof(dp));
	for (i = n; i >= 0; i--)
	{
		for (j = s; j >= 0; j--)
		{
			if (i == n && j == s)continue;
			dp[i][j] = (dp[i + 1][j + 1] * (n - i)*(s - j) + dp[i + 1][j] * (n - i)*j + 
				dp[i][j + 1] * i*(s - j) + n * s) / (n*s - i * j);
			//化简后的状态转移方程
		}
	}
	printf("%.4lf\n", dp[0][0]);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值