标签:
好久之前学过,记得是一次亚洲区的前几天看了看概率dp,然后亚洲区就出了一道概率dp,当时虽然做上了,但是感觉有很多地方没懂,今天起早温习了一下,觉得很多地方茅塞顿开,果然学习的话早上效果最好了。
首先来看一道最基础概率dp
题意是,有一个软件,有s个子系统,会产生n种bug。
某个程序员一天能发现一个bug,这个bug是这n种bug中的一种,然后发生在某个子系统中。
问,找到所有的n种bug,且每个子系统都找到bug,这样所要的天数,的期望。
期望,可以分解成多个子期望的加权和,权为子期望发生的概率
所以: 我首先想到了一个这样的公式dp[x][y] = dp[x][y]*p1+dp[x-1][y-1]*p2+dp[x][y-1]*p3+dp[x-1][y]*p4
dp[x][y]代表已经有x种bug并且有y个系统至少有一个bug的期望值
我们知道他是从自身以及他的前几种状态推导过来,乍一看这个公式应该是对的,但是dp[n][m]会无穷大,因为他的期望是没有停止状态的,也就是题意要求的应该是到达n,m状态时停止。
那么我们又可以从倒推的角度去考虑这个问题,dp[x][y]表示的是已经有x种bug并且有y个系统至少有一种bug的时候还需要多少步能够到达dp[n][m]的状态。
那么公式又变成了这样dp[x][y] = dp[x+1][y+1]*p1+dp[x+1][y]*p2+dp[x][y+1]*p3+dp[x][y]*p4+1
也就是dp[x][y] = dp[x+1][y+1] *(n-x)*(m-y)/n/m+dp[x+1][y]*(n-x)*y/n/m+dp[x][y+1]*x*(m-y)/n/m+dp[x][y]*x*y/n/m+1
将dp[x][y]合并得dp[x][y](1-x*y/n/m) = dp[x+1][y+1] *(n-x)*(m-y)/n/m+dp[x+1][y]*(n-x)*y/n/m+dp[x][y+1]*x*(m-y)/n/m+1
1.poj2096,就是上面的题
#include<stdio.h> #include<string.h> #include<iostream> using namespace std; double dp[1004][1004]; int main(){ int n, m; scanf("%d%d", &n, &m); for(int i =0 ;i <= n+1; i++){ for(int k = 0; k <= m+1; k++){ dp[i][k]= 0; } } for(int x = n; x >= 0; x--){ for(int y = m; y >=0; y--){ if(x == n && y ==m)dp[x][y] = 0; else dp[x][y]= (1+dp[x+1][y+1] *(n-x)*(m-y)/n/m+dp[x+1][y]*(n-x)*y/n/m+dp[x][y+1]*x*(m-y)/n/m)/(1.0-1.0*x*y/n/m); } } printf("%.4f\n", dp[0][0]); }
标签:
原文地址:http://www.cnblogs.com/icodefive/p/4712477.html