题目链接:poj 2096 Collecting Bugs
这道题目,网上找的做法都是一样的,感觉都没有很好的讲述为什么这么做是对的,而其他的就不行
这是本人第一道概率dp题目,随便yy的,难免错误,如果看到错误的话,万望指出
题意:
很容易想到的是状态是: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; }