POJ2096(概率dp)

题目链接:http://poj.org/problem?id=2096

题意:一道入门的概率dp题目。一个系统有n种bug和s个子系统,bug的数量是无限的,每次每天可以从s个子系统中找到一个bug,每种bug的概率都是相等的,现求s个子系统中找到n种bug的平均天数,要求每个子系统中至少找到一种bug

思路:dp[i][j] 表示已经在j个子系统中找到了i种bug,剩余所需要的平均天数。

          显然dp[n][s] = 0,已经在s个子系统中找到了n种bug,所以等于已经完成了任务,即最终要求的是dp[0][0]

          那么dp[i][j] 可以转移的状态为四种:

①i,j+1;所发现的bug在新子系统中,此前已经已经发现相同的种类的bug;
②i+1,j+1;所发现的bug在新子系统中,此前还未发现过此类bug;
③i,j;所发现的bug在旧子系统中,此前已经已经发现相同的种类的bug;
④i+1,j;所发现的bug在旧子系统中,此前还未发现过此类bug;

      以上四种可能性发生的概率分别可以计算.

      其转移方程就是 dp[i][j] = 1 + dp[i+1][j] * p1 + dp[i+1][j+1] * p2 + dp[i][j] * p3 + dp[i][j+1] * p4;  //p1....p4分别是各个状态的概率

     把等式右边的dp[i][j]*p3移到右边,整理得:

     dp[i][j] = (1.0+ dp[i+1][j]*p2 + dp[i][j+1]*p3 + dp[i+1][j+1]*p4)/(1.0-p1);

AC代码:

#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<queue> 
#include<cstdio>
#define inf 0x3f3f3f3f
using namespace std;
double dp[1005][1005];
typedef long long ll;
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
    int n,s;
    while(scanf("%d%d",&n,&s)!=EOF){
     memset(dp,0,sizeof(dp));
	for(int i = n;i>=0;i--){
		for(int j = s;j>=0;j--){
			if(i == n && j == s) continue;
			 double p1 = 1.0*i/n*j/s;
			 double p2 = 1.0*(n-i)/n*j/s; 
			 double p3 = 1.0*i/n*(s-j)/s;
			 double p4 = 1.0*(n-i)/n*(s-j)/s;
			dp[i][j] = (1.0+ dp[i+1][j]*p2 + dp[i][j+1]*p3 + dp[i+1][j+1]*p4)/(1.0-p1);
		}
      }
	
	 printf("%.4f
",dp[0][0]);  
	}
	return 0;
} //

原文地址:https://www.cnblogs.com/AaronChang/p/12129621.html