src:http://poj.org/problem?id=2096
题意: 一个软件有s个子系统,会产生n种bug 某人一天发现一个bug,这个bug属于一个子系统,属于一个分类 每个bug属于某个子系统的概率是1/s,属于某种分类的概率是1/n 问发现n种bug,每个子系统都发现bug的天数的期望。
解答:https://blog.csdn.net/morgan_xww/article/details/6774708 https://www.cnblogs.com/kuangbin/archive/2012/10/02/2710606.html
“转自kuangbin博客”
dp[i][j]表示已经找到i种bug,j个系统的bug,达到目标状态的天数的期望 dp[n][s]=0;要求的答案是dp[0][0]; dp[i][j]可以转化成以下四种状态: dp[i][j],发现一个bug属于已经有的i个分类和j个系统。概率为(i/n)*(j/s); dp[i][j+1],发现一个bug属于已有的分类,不属于已有的系统.概率为 (i/n)*(1-j/s); dp[i+1][j],发现一个bug属于已有的系统,不属于已有的分类,概率为 (1-i/n)*(j/s); dp[i+1][j+1],发现一个bug不属于已有的系统,不属于已有的分类,概率为 (1-i/n)*(1-j/s);整理便得到转移方程
整理得到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],所以我们要再整理一下是得右边没有未知的dp[i][j] ~~~
dp总得从已知的开始推,这里已知的是[n][s],而且期望就是到目标的一种可能值,所以只有dp[n][s]已知 , 因此一般求概率是正推,求期望是逆推。通过题目可以体会到这点。
ac代码:
#include<bits/stdc++.h> using namespace std; #define per(i,a,b) for(int i=a;i <= b;i++) #define max(a,b) a=max(a,b) #define min(a,b) a=min(a,b) #define sz(x) (int)x.size() typedef long long ll; ll gcd(ll a,ll b){while(b){ll t=b;b=a%b;a=t;}return a;} const int inf=0x3f3f3f3f; const int mod=1000000007; #define siz 1005 int n,s; double dp[siz][siz];//dp[i][j]为找到i种bug j种系统的期望天数 int main() { scanf("%d%d",&n,&s); dp[n][s]=0.0; for(int i=n;i>=0;i--){ for(int j=s;j>=0;j--){ if(i==n&&j==s)continue; dp[i][j]=(n*s+(n-i)*j*dp[i+1][j]+i*(s-j)*dp[i][j+1]+(n-i)*(s-j)*dp[i+1][j+1])/(n*s-i*j);//如果没有[n][s]特判,这里就会除以0,runtime error } } printf("%.4f ",dp[0][0]); return 0; }