Collecting Bugs(概率dp)

LINK

题目

Collecting Bugs(概率dp)_第1张图片

大致翻译

每天可以从s个子系统中查找1个bug。问发现n中bug并且每个子系统至少发现1个bug的期望。

思路

maybe:概率正推,期望逆推
期望可以分解成多个子期望的加权和,权为子期望发生的概率,即 E ( a A + b B + . . . ) = a E ( A ) + b E ( B ) + . . . E(aA+bB+...) = aE(A) + bE(B) +... E(aA+bB+...)=aE(A)+bE(B)+...
d p [ i ] [ j ] dp[i][j] dp[i][j]表示在j个子系统中找到i中bug的期望。
d p [ n ] [ s ] dp[n][s] dp[n][s]初始化为0,因为已经达到目标;dp[0][0]即所求答案。
d p [ i ] [ j ] dp[i][j] dp[i][j]状态转化为以下四种:(概率)

  1. d p [ i ] [ j ] dp[i][j] dp[i][j],不增加 p 1 = ( i / n ) ∗ ( j / s ) p1=(i/n)*(j/s) p1=(i/n)(j/s) 即:发现一个bug属于已经找到的i种bug和j个子系统中
  2. d p [ i + 1 ] [ j ] dp[i+1][j] dp[i+1][j],只增加bug种类 p 2 = ( 1 − i / n ) ∗ ( j / s ) p2=(1-i/n)*(j/s) p2=(1i/n)(j/s) 即:发现一个bug属于新的一种bug,但属于已经找到的j种子系统
  3. d p [ i ] [ j + 1 ] dp[i][j+1] dp[i][j+1],只增加系统 p 3 = ( i / n ) ∗ ( 1 − j / s ) p3=(i/n)*(1-j/s) p3=(i/n)(1j/s) 即:发现一个bug属于已经找到的i种bug,但属于新的子系统
  4. d p [ i + 1 ] [ j + 1 ] dp[i+1][j+1] dp[i+1][j+1],增加bug的同时增加系统 p 4 = ( 1 − i / n ) ∗ ( 1 − j / s ) p4=(1-i/n)*(1-j/s) p4=(1i/n)(1j/s) 即:发现一个bug属于新的一种bug和新的一个子系统

所以式子为: d p [ i , j ] = p 1 ∗ d p [ i , j ] + p 2 ∗ d p [ i + 1 , j ] + p 3 ∗ d p [ i , j + 1 ] + p 4 ∗ d p [ i + 1 , j + 1 ] + 1 ; dp[i,j] = p1*dp[i,j] + p2*dp[i+1,j] + p3*dp[i,j+1] + p4*dp[i+1,j+1] + 1; dp[i,j]=p1dp[i,j]+p2dp[i+1,j]+p3dp[i,j+1]+p4dp[i+1,j+1]+1;
(期望可以分解成多个子期望的加权和,权为子期望发生的概率)
由于等式两边都有 d p [ i , j ] dp[i,j] dp[i,j]所以要将式子化简(在代码中体现)

代码

#include 
using namespace std;
#define ll long long
//#define int long long
const int N = 2e5+10;
double dp[1010][1010];
signed main(){
//	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int n,s;cin>>n>>s;
	for(int i=n;i>=0;i--){
		for(int j=s;j>=0;j--){
			if(i==n&&s==j)dp[i][j]=0.0;
			else dp[i][j]=1.0*(1.0*(n-i)*j*dp[i+1][j]+1.0*i*(s-j)*dp[i][j+1]+1.0*(n-i)*(s-j)*dp[i+1][j+1]+1.0*n*s)/(n*s-i*j);
		}
	}
	printf("%.4lf\n",dp[0][0]);
	return 0;
}

你可能感兴趣的:(dp,算法,c++,动态规划)