[概率DP] Topcoder SRM687div2 1000 Queueing

题意:
两列队伍,左边有 len1 个人,右边有 len2 个人,问事件左边没人但右边有人的概率。
两边收银员各有一个经验值参数 p F(p,k)=(1/p)(11/p)k1 表示经验值为 p 的收银员恰好花费 k 秒完成一次收银的概率。
题解:
首先发现 F(p,k) 十分眼熟,满足几何分布,所以每秒成功收银的概率是 1/p ,设左边成功收银概率 a=1/p1 ,右边为 b=1/p2
设左边没人但右边有人为事件 A ,则答案是求 P(A)
然后就是DP, DP[i][j] 表示左边有 i 人右边有 j 人时达成事件 A 的概率。
然后转移有四个方向:

  1. 左边成功但右边失败,概率是 a(1b)
  2. 左边成功且右边成功,概率是 ab
  3. 左边失败但右边成功,概率是 (1a)b
  4. 左边失败且右边失败,概率是 (1a)(1b)

整理出转移方程。
DP[i][j]=DP[i1][j]a(1b)+DP[i1][j1]ab+DP[i][j1](1a)b+DP[i][j](1a)(1b)

解出 DP[i][j]=(DP[i1][j]a(1b)+DP[i1][j1]ab+DP[i][j1](1a)b)/(1(1a)(1b))

初始条件为 DP[0][0]=0DP[0][i]=1(i>=1)

// BEGIN CUT HERE

// END CUT HERE
#line 5 "Queueing.cpp"
#include<vector>
#include<algorithm>
#include<string.h>
using namespace std;
double dp[1005][1005];
class Queueing {
    private:
        void init(){
            memset(dp, 0, sizeof(dp));
        }
    public:
        double probFirst(int len1, int len2, int p1, int p2) {
            init();
            for(int i = 1; i <= len2; ++i) dp[0][i] = 1;
            double a = 1.0/p1, b = 1.0/p2;
            for(int i = 1; i <= len1; ++i){
                for(int j = 1; j <= len2; ++j){
                    dp[i][j] = dp[i-1][j]*a*(1-b)+dp[i][j-1]*(1-a)*b+dp[i-1][j-1]*a*b;
                    dp[i][j] /= (1-(1-a)*(1-b));
                }
            }
            return dp[len1][len2];
        }
};

你可能感兴趣的:(dp,topcoder)