zoukankan      html  css  js  c++  java
  • HDU 4089 Activation:概率dp + 迭代【手动消元】

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4089

    题意:

      有n个人在排队激活游戏,Tomato排在第m个。

      每次队列中的第一个人去激活游戏,有可能发生以下四种情况:

        (1)激活失败,继续留在队首,等待下一次激活。

        (2)连接失败,退到队尾。

        (3)激活成功,离开队列。

        (4)服务器瘫痪。

      发生的概率分别为p1,p2,p3,p4。

      问你服务器瘫痪时,Tomato的位置<=k的概率。

    题解:

      表示状态:

        dp[i][j] = probability

        表示当前还有i个人在排队,Tomato在位置j。在这以及之后服务器瘫痪时,Tomato位置<=k的概率。

      找出答案:

        ans = dp[n][m]

      如何转移:

        按着四种情况分别写就好:

          (1)j == 1:  dp[i][1] = dp[i][1]*p1 + dp[i][i]*p2 + p4

          (2)2<=j<=k: dp[i][j] = dp[i][j]*p1 + dp[i][j-1]*p2 + dp[i-1][j-1]*p3 + p4

          (3)k<j<=i:  dp[i][j] = dp[i][j]*p1 + dp[i][j-1]*p2 + dp[i-1][j-1]*p3

        令p21 = p2/(1-p1), p31 = p3/(1-p1), p41 = p4/(1-p1)

        化简得:

          (1)j == 1:  dp[i][1] = dp[i][i]*p21 + p41

          (2)2<=j<=k: dp[i][j] = dp[i][j-1]*p21 + dp[i-1][j-1]*p31 + p41

          (3)k<j<=i:  dp[i][j] = dp[i][j-1]*p21 + dp[i-1][j-1]*p31

      边界条件:

        dp[1][1] = dp[1][1]*(p1+p2) + p4

        解得:dp[1][1] = p4/(1-p1-p2)

      然而这并没有结束……

      转移的时候显然先枚举i,在枚举j。

      可是j在当前的i中,是往两个方向转移的:

        dp[i][j]需要用到前面的dp[i][j-1],而dp[i][1]又用到了后面的dp[i][i]……QAQ

      所以迭代一下,先解出dp[i][1]:

        每一个dp[i][j]都可以表示成 dp[i][j] = p*dp[i][1] + c 的形式。

        显然对于最初的dp[i][1]: p = 1, c = 0

        对于后面的每一个dp[i][j]: p *= p21, c = c*p21 + dp[i-1][j-1]*p31 + (j<=k)*p41

        这样就由前一项的p和c,推出了当前的p和c。

        推啊推,直到推出了:dp[i][i] = p*dp[i][1] + c

        这时就可以代入解方程了:

          代入原来的递推式dp[i][1] = dp[i][i]*p21 + p41中

          得到:dp[i][1] = p21*(p*dp[i][1] + c) + p41

          解得:dp[i][1] = (p21*c + p41)/(1 - p*p21)

      然而还是没有结束……

      这题丧病卡空间……所以用滚动数组。

      由于转移的时候要用到dp[0][j]的0值,所以第一维MAX_N变成3,i=1,2轮流使用。

      这样就好啦~~~

    AC Code:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 #define MAX_N 2005
     5 #define cal(x) ((!(x))?0:(2-((x)&1)))
     6 
     7 using namespace std;
     8 
     9 int n,m,k;
    10 double p1,p2,p3,p4;
    11 double dp[3][MAX_N];
    12 
    13 int main()
    14 {
    15     memset(dp,0,sizeof(dp));
    16     while(scanf("%d%d%d%lf%lf%lf%lf",&n,&m,&k,&p1,&p2,&p3,&p4)!=EOF)
    17     {
    18         if(p4<1e-5)
    19         {
    20             printf("0.00000
    ");
    21             continue;
    22         }
    23         double p21=p2/(1-p1);
    24         double p31=p3/(1-p1);
    25         double p41=p4/(1-p1);
    26         dp[cal(1)][1]=p4/(1-p1-p2);
    27         for(int i=1;i<=n;i++)
    28         {
    29             if(i>1)
    30             {
    31                 double p=1.0,c=0;
    32                 for(int j=2;j<=i;j++)
    33                 {
    34                     p*=p21;
    35                     c=c*p21+dp[cal(i-1)][j-1]*p31;
    36                     if(j<=k) c+=p41;
    37                 }
    38                 dp[cal(i)][1]=(c*p21+p41)/(1-p*p21);
    39             }
    40             for(int j=2;j<=i;j++)
    41             {
    42                 dp[cal(i)][j]=dp[cal(i)][j-1]*p21+dp[cal(i-1)][j-1]*p31;
    43                 if(j<=k) dp[cal(i)][j]+=p41;
    44             }
    45         }
    46         printf("%.5f
    ",dp[cal(n)][m]);
    47     }
    48 }
  • 相关阅读:
    Android优化之软引用和弱引用
    Android中Service与IntentService的使用比较
    Android配置文件,所有权限
    为什么Android手机总是越用越慢?
    Android之安全机制
    JDK8-函数式接口
    JDK8-Java Streams 收集器
    JDK8- java.util.stream 库笔记
    MVVM核心实现代码(简易实现)
    JavaScript小总结
  • 原文地址:https://www.cnblogs.com/Leohh/p/8124415.html
Copyright © 2011-2022 走看看