zoukankan      html  css  js  c++  java
  • 【HDU4089】Activation-概率DP好题

    测试地址:Activation
    题目大意: Tomato要在服务器上激活一个游戏,一开始服务器序列中有N个人,他排在第M位,每次服务器会对序列中第一位的玩家进行激活,有四种结果:
    1.有p1的概率会激活失败,这时候序列的状态是不变的。
    2.有p2的概率第一位的玩家会连接错误,这时候序列中第一位的玩家会成为最后一位,其他玩家相对位置不变。
    3.有p3的概率第一位的玩家激活成功,这时候第一位的玩家会离开序列。
    4.有p4的概率服务器崩溃,发生这件事之后所有玩家都不能激活了。
    求Tomato遇到服务器崩溃并且在服务器崩溃时处于前K位的概率。
    做法:这一道题是概率DP,而且是一道非常好的题目。
    题意比较复杂,但是看到概率,我们就应该想到用DP来求概率。设f(i,j)为从序列中有i人,Tomato在第j位的状态开始到达目标状态(遇到服务器崩溃并且在服务器崩溃时处于前K位)的概率,有以下状态转移方程(不懂怎么推出来的可以结合题意理解一下):
    j=1f(i,j)=f(i,j)×p1+f(i,i)×p2+p4
    1<jkf(i,j)=f(i,j)×p1+f(i,j1)×p2+f(i1,j1)×p3+p4
    k<jif(i,j)=f(i,j)×p1+f(i,j1)×p2+f(i1,j1)×p3
    注意到有些状态之间是会循环引用的,那是不是就不能用DP来解了呢?不是。事实上,在这些状态中进行概率转移的过程称为马尔可夫过程,而马尔可夫过程平衡的条件是所有状态转移方程被同时满足,我们要求的就是平衡状态下的f(n,m)
    于是我们把上列方程化简,方程两侧同减f(i,j)×p1,然后同除1p1,就得到新的方程组。根据上列方程我们知道f(1,1)=p4/(1p1p2),因此可以在f(2,x)的方程组中作为常数计算。那么怎么解f(2,x)这样循环引用的方程组呢?其实很简单,我们已经有了f(2,1)关于f(2,2)的表达式,那么我们只要迭代推出f(2,2)关于f(2,1)的表达式,就可以把这两个数解出来。对于f(i,x)的方程组也是同理,因为f(i1,x)已经求出,可以在这个方程组中作为常数使用,那么我们就可以迭代求出f(i,i)关于f(i,1)的表达式,然后解出f(i,1)(或f(i,i)),再通过DP推出所有的f(i,x)即可。这样一步一步解下去,最后就可以求出f(n,m)的值了。
    这样我们就解决了这一题,时间复杂度为O(N2)。需要注意一点,如果不做任何特判,上述计算过程可能会溢出,事实证明,溢出就代表着最终概率无限接近0,而最终概率无限接近0就代表p4<eps,所以把这种情况判掉之后,其余情况都可以利用上述计算过程得出。
    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define eps 1e-10
    using namespace std;
    int n,m,k;
    double p1,p2,p3,p4,f[2010][2010];
    
    int main()
    {
        while(scanf("%d%d%d%lf%lf%lf%lf",&n,&m,&k,&p1,&p2,&p3,&p4)!=EOF)
        {
            if (p4<eps) {printf("0.00000
    ");continue;}
            f[1][1]=p4/(1-p1-p2);
            for(int i=2;i<=n;i++)
            {
                double s1=1,s2=0;
                for(int j=2;j<=i;j++)
                {
                    if (j<=k)
                    {
                        s1=s1*p2/(1-p1);
                        s2=(s2*p2+f[i-1][j-1]*p3+p4)/(1-p1);
                    }
                    else
                    {
                        s1=s1*p2/(1-p1);
                        s2=(s2*p2+f[i-1][j-1]*p3)/(1-p1);
                    }
                }
                s1=1-s1*p2/(1-p1);
                s2=(p4+s2*p2)/(1-p1);
                f[i][1]=s2/s1;
                for(int j=2;j<=i;j++)
                {
                    if (j<=k) f[i][j]=(f[i][j-1]*p2+f[i-1][j-1]*p3+p4)/(1-p1);
                    else  f[i][j]=(f[i][j-1]*p2+f[i-1][j-1]*p3)/(1-p1);
                }
            }
            printf("%.5lf
    ",f[n][m]);
        }
    
        return 0;
    }
    
  • 相关阅读:
    webrtc连接方法——TURN服务器和STUN服务器作用简介
    IM音视频即时通讯系统EasyRTC如何利用webrtc技术进行优化和发展?
    TSINGSEE青犀视频平台可以实现音视频混流吗?
    深入浅出Java 重定向和请求转发的区别
    特征工程-特征提取
    cart剪枝
    决策树算法简介
    逻辑回归介绍
    sklearn模型的保存和加载
    celery 定时任务时间篇
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793582.html
Copyright © 2011-2022 走看看