poj2096(概率dp)

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\n",dp[0][0]);
    return 0;
}

 

posted @ 2018-08-17 23:23  WindFreedom  阅读(523)  评论(0编辑  收藏  举报