• [HDU 4089]Activation[概率DP]


    题意:

    有n个人排队等着在官网上激活游戏。Tomato排在第m个。
    对于队列中的第一个人。有以下情况:
    1、激活失败,留在队列中等待下一次激活(概率为p1)
    2、失去连接,出队列,然后排在队列的最后(概率为p2)
    3、激活成功,离开队列(概率为p3)
    4、服务器瘫痪,服务器停止激活,所有人都无法激活了。
    求服务器瘫痪时Tomato在队列中的位置<=k的概率

    思路:
    概率DP.

    找不到思路的主要原因是不清楚dp数组到底用来表示什么. 进而无法合适地分析状态转移.

    概率DP是将从当前状态到最终状态一系列多重的选择"封装", 表示为一个最终结果, 然后根据题意的转移方式, 严格分离等号左右两边(常有自我循环, 若是不刻意分别对待容易混乱). 式子列好之后再考虑怎么解.

    设dp[i][j]表示i个人排队,Tomato排在第j个位置,达到目标状态的概率(j<=i)
    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;
    k<j<=i:  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;
    k<j<=i:  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][1~i]时等到下列i个方程
    j==1:   dp[i][1]=a*dp[i][i]+b;
    2<=j<=k:dp[i][j]=a*dp[i][j-1]+d[j];
    k<j=i:  dp[i][j]=a*dp[i][j-1]+c[j];
    其中c[j]都是常数了。上述方程可以解出dp[i]了。
    首先是迭代得到 dp[i][i].然后再代入就可以得到所有的dp[i]了。

    这个迭代...就是推出展开之后的式子...秦九韶算法><

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

    (若不是看题解...一个eps就够挖的了...)

    参考:http://www.cnblogs.com/kuangbin/archive/2012/10/03/2710987.html

    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    using namespace std;
    const int MAXN = 2005;
    const double EPS = 1e-6;
    int m,n,k;
    double p1,p2,p3,p4;
    double c[MAXN], d[MAXN], a, b, dp[MAXN][MAXN];
    int main()
    {
        while(scanf("%d%d%d%lf%lf%lf%lf",&n,&m,&k,&p1,&p2,&p3,&p4)==7)
        {
            if(p4<EPS)
            {
                printf("0.00000
    ");
                continue;
            }
            a = p2/(1-p1);
            b = p4/(1-p1);
            double p31 = p3/(1-p1);
            dp[1][1] = b/(1-a);
            for(int i=2;i<=n;i++)
            {
                for(int j=1;j<i;j++)
                    c[j] = p31*dp[i-1][j],d[j] = c[j] + b;
                double tmp = 0, exp = 1;
                for(int j=i-1;j>0;j--)
                {
                    if(j>=k)
                        tmp += exp*c[j];
                    else
                        tmp += exp*d[j];
                    exp *= a;
                }
                tmp += exp*b;
                exp *= a;
                dp[i][i] = tmp/(1-exp);
                dp[i][1] = a*dp[i][i] + b;
                for(int j=2;j<i;j++)
                {
                    if(j<=k)    dp[i][j] = a*dp[i][j-1] + d[j-1];
                    else        dp[i][j] = a*dp[i][j-1] + c[j-1];
                }
            }
            printf("%.5lf
    ",dp[n][m]);
    
        }
    }
    


  • 相关阅读:
    springboot + self4j 学习笔记
    git 创建本地分支,并且推送到远程分支
    windows 下生成 ssh key
    Topshelf
    ADSL拨号连接
    EF中使用Contains方法
    elasticsearch中的概念简述
    CriticalFinalizerObject的作用
    sqlserver中的统计语法
    Windbg简单介绍
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3367667.html
Copyright © 2020-2023  润新知