博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HDU 4089 Activation:概率dp + 迭代【手动消元】
阅读量:4988 次
发布时间:2019-06-12

本文共 2804 字,大约阅读时间需要 9 分钟。

题目链接:

题意:

  有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 
2 #include
3 #include
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\n");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\n",dp[cal(n)][m]);47 }48 }

 

转载于:https://www.cnblogs.com/Leohh/p/8124415.html

你可能感兴趣的文章
python反射
查看>>
USACO 2017 February Gold
查看>>
XML DOM解析 基础概念
查看>>
jQuery取得select选择的文本与值
查看>>
Android入门系列002----普通控件使用
查看>>
YARN框架详解
查看>>
topshelf windows服务
查看>>
Mac OS X下重启apache
查看>>
Unity3D中Animator动画控制器组件的相关使用
查看>>
Mayan游戏
查看>>
The New Jordans 2013 released a comeback
查看>>
SQL实战(四)
查看>>
LEETCODE —— Unique Binary Search Trees [动态规划]
查看>>
栈溢出利用
查看>>
JS核心知识点:DOM\BOM\EVENT
查看>>
嵌入式软件设计第8次试验
查看>>
Datenstruktur und Algorithmus
查看>>
DLL劫持技术详解(lpk.dll)
查看>>
『干货』分享你最喜欢的技巧和提示(Xcode,objective-c,swift,c...等等)
查看>>
WPF教程六:布局之Grid面板(转)
查看>>