HDU 4089 Activation (概率DP )

来源:互联网 发布:阿里域名隐私保护 编辑:程序博客网 时间:2024/05/16 17:35

参考1 参考2

题目:仙5的激活序列。有以下4种情况:

1、注册失败,但是不影响队列顺序 ,概率为p1

2、连接失败,队首的人排到队尾,概率为p2

3、注册成功,队首离开队列,概率为p3

4、服务器崩溃,激活停止,概率为p4

求主角的位置在K以内,而且服务器崩溃的概率

http://acm.hdu.edu.cn/showproblem.php?pid=4089 

题解:
是一个概率题,分析一下题意后发现和“dp求期望”的题目有点像,因为其中都有一种死循环的可能,
该题中,如果总是发生p1概率的情况那就是死循环了。然后想到一个二维dp:
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];

先解出dp[i][i],进而可以得到dp[i][1],剩下的就可以递推出来了

#include<iostream>#include<cstring>#include<cstdio>#include<queue>using namespace std;#define ll long long#define prt(k) cerr<<#k" = "<<k<<endlconst int N = 2014;double dp[N][N];double p1, p2, p3, p4;int n, m, K;int main(){    while(cin>>n>>m>> K >> p1>>p2>>p3>>p4)    {        if(p3 + p4 < 1e-8) { puts("0.00000"); continue; }        memset(dp, 0, sizeof dp);        dp[1][1] = p4 / (p3 + p4);       // prt(dp[1][1]);        p2 /= 1 - p1;        p3 /= 1 - p1;        p4 /= 1 - p1;        double pp[N], c[N];      //  prt(p2); prt(p3);        c[1] = p4;        pp[0] = 1;        for(int i=1;i<=n;i++) pp[i]=pp[i-1]*p2;  ///pp[i] = p2 ^ i        for(int i=2;i<=n;i++)        {            for (int j=2;j<=K;j++)                c[j] =  dp[i-1][j-1] * p3 + p4;            for (int j=K+1;j<=i;j++)                c[j] = dp[i-1][j-1] * p3;            double tmp = 0;            for (int j=1; j<=i; j++)                tmp += pp[i-j] * c[j];            dp[i][i] = tmp / (1 - pp[i]);            dp[i][1] = dp[i][i] * p2 + p4;            for(int j=2;j<i;j++)                dp[i][j] = dp[i][j-1] * p2 + c[j];        }        printf("%.5f\n", dp[n][m]);    }}



0 0
原创粉丝点击