【概率DP】 HDU 4089 Activation

通道

题意:有n个人排队等着在官网上激活游戏。Tomato排在第m个。对于队列中的第一个人:

  1、激活失败,留在队列中等待下一次激活(概率为p1)

  2、失去连接,出队列,然后排在队列的最后(概率为p2)

  3、激活成功,离开队列(概率为p3)

  4、服务器瘫痪,服务器停止激活,所有人都无法激活了。求服务器瘫痪时Tomato在队列中的位置<=k的概率

思路:

dp[i][j]表示队列中有i个人,Tomato排在第j个,能发生所求事件的概率。
显然,dp[n][m]即为所求。
j == 1 : dp[i][1] = p1*dp[i][1] + p2*dp[i][i]   + p4;
2<=j<=k: dp[i][j] = p1*dp[i][j] + p2*dp[i][j-1] + p3*dp[i-1][j-1] + p4;
j > k  : dp[i][j] = p1*dp[i][j] + p2*dp[i][j-1] + p3*dp[i-1][j-1];
化简:
j == 1 : dp[i][1] = p*dp[i][i]   + p41;
2<=j<=k: dp[i][j] = p*dp[i][j-1] + p31*dp[i-1][j-1] + p41;
j > k  : dp[i][j] = p*dp[i][j-1] + p31*dp[i-1][j-1];
其中:
p   = p2 / (1 - p1);
p31 = p3 / (1 - p1);
p41 = p4 / (1 - p1);
现在可以循环 i = 1 -> n 递推求解dp[i],所以在求dp[i]时,dp[i-1]就相当于常数了,
设dp[i][j]的常数项为c[j]:
j == 1 : dp[i][1] = p*dp[i][i]   + c[1];
2<=j<=k: dp[i][j] = p*dp[i][j-1] + c[j];
j > k  : dp[i][j] = p*dp[i][j-1] + c[j];
在求dp[i]时,就相当于求“i元1次方程组”:
dp[i][1] = p*dp[i][i] + c[1];
dp[i][2] = p*dp[i][1] + c[2];
dp[i][3] = p*dp[i][2] + c[3];
...

 dp[i][i] = p*dp[i][i-1] + c[i];


注意特判一种情况。就是p4<eps时候,就不会崩溃了,应该直接输出0

代码:

#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

double dp[2][2001];
double c[2005], pp[2005];

int main() {
    int    n, m, k;
    double p1, p2, p3, p4;
    while ( scanf("%d%d%d", &n, &m, &k) != EOF ) {
        scanf("%lf%lf%lf%lf", &p1, &p2, &p3, &p4);
        if ( fabs(1 - p1 - p2) < 1e-9 ) {
            puts("0.00000");
            continue;
        }
        double p   = p2 / (1 - p1);
        double p31 = p3 / (1 - p1);
        double p41 = p4 / (1 - p1);
        pp[0] = 1;
        for (int i = 1; i <= n; i++)
            pp[i] = pp[i-1] * p;
        dp[1][1] = p4 / (1 - p1 - p2);
        c[1]     = p41;
        int t = 1;
        for (int i = 2; i <= n; i++){
            t ^= 1;
            for (int j = 2; j <= k; j++)
                c[j] = dp[t ^ 1][j-1] * p31 + p41;
            for (int j = k+1; j <= i; j++)
                c[j] = dp[t ^ 1][j-1] * p31;
            double tmp = 0.0;
            for (int j = i; j > 0; j--)
                tmp += pp[i-j] * c[j];
            dp[t][i] = tmp / (1 - pp[i]);
            dp[t][1] = p * dp[t][i] + p41;
            for (int j = 2; j < i; j++)
                dp[t][j] = p * dp[t][j-1] + c[j];
        }
        printf("%.5f\n", dp[t][m]);
    }
    return 0;
}
View Code

 

posted @ 2015-08-12 15:41  mithrilhan  阅读(154)  评论(0编辑  收藏  举报