这道题目,网上找的做法都是一样的,感觉都没有很好的讲述为什么这么做是对的,而其他的就不行
这是本人第一道概率dp题目,随便yy的,难免错误,如果看到错误的话,万望指出
题意:
- 软件有s个子系统,会产生n种bug。
- 某人一天发现一个bug,这个bug属于某种bug,发生在某个子系统中,都是等可能的情况
- 求找到所有的n种bug,且每个子系统都找到bug,这样所要的天数的期望。
很容易想到的是状态是:dp[ i ][ j ] 表示 发生了i种bug ,j 个子系统的期望,如果当前是dp[ i ][ j ] 那么很容易 转移到的状态是:
dp[ i ][ j ] p1 = i*i/(n*s)
dp[ i+1 ][ j ] p2= (n-i)*j/(n*s)
dp[ i ][ j +1 ] p3=i*(s-j)/(n*s)
dp[i +1][ j + 1] p4=(n-i)*(s-j)/(n*s)
再仔细分析的话,发现 状态表示 dp[ i ][ j ] 的状态表示是错误的,例如:第一天dp[ 1 ][ 1 ] = 1 , 那么第二天dp[ 1 ][ 1 ]呢?反正期望肯定会变多,期望本身的定义就是无穷 , 如果在加入一维 表示天数的话,几乎不可能……
如果我们逆着推,dp[i][j]表示已经找到i种bug,并存在于j个子系统中,要达到目标状态的天数的期望。很明显 dp[ n ][ s ] =0, 这样我们就算的每个dp[ i ][ j ] 就是最终答案了,不会随着天数的改变而改变了
dp[i,j] = p1*dp[i,j] + p2*dp[i+1,j] + p3*dp[i,j+1] + p4*dp[i+1,j+1] + (p1*1 +p2*1 +p3*1 + p4*1); 由于 p1 + p2 + p3 +p4 == 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;
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
double dp[1010][1010];
int main()
{
int n,s;
while(scanf("%d%d",&n,&s)==2)
{
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=i*j*1.0/(n*s);
double p2=(n-i)*j*1.0/(n*s);
double p3=i*(s-j)*1.0/(n*s);
double p4=(n-i)*(s-j)*1.0/(n*s);
dp[i][j]=(p2*dp[i+1][j]+p3*dp[i][j+1]+p4*dp[i+1][j+1]+1)/(1-p1);
}
//cout<<dp[1][1]<<endl;
printf("%.4f\n",dp[0][0]);
}
return 0;
}