hdu 4089
题意:有n个人排队等着在官网上激活游戏。Tomato排在第m个。
对于队列中的第一个人。有一下情况:
1、激活失败,留在队列中等待下一次激活(概率为p1)
2、失去连接,出队列,然后排在队列的最后(概率为p2)
3、激活成功,离开队列(概率为p3)
4、服务器瘫痪,服务器停止激活,所有人都无法激活了。
求服务器瘫痪时Tomato在队列中的位置<=k的概率
解析:
概率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;(此时tomato只有三种选择,不能选注册成功)
2<=j<=k: dp[i][j]=p1*dp[i][j]+p2*dp[i][j-1]+p3*dp[i-1][j-1]+p4;(此时,队列里的第一人有4中可能选择,若为p1对应事件,那么第一人位置不动,则tomato位置不动,这种情况概率为p1*dp[i][j] ,若为p2对应事件,那么第一人排到最后,tomato前进一位,对应概率p2*dp[i][i]······。)
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]; ③
其中:
p21=p2/(1-p1);
p31=p3/(1-p1)
p41=p4/(1-p1)
我们可以求得dp[1][1] = p41/(1-p21);
在①中dp[i][i]为未知数(dp[i-1][j-1]以求)
而在②或③中,dp[i][j]都是由前一步的dp[i][j-1]得来,即比如:
dp[3][1]=dp[3][3]+c1;
dp[3][2]=dp[3][1]*p31+c2;
dp[3][3]=dp[3][2]*p31+c3;
因为dp[3][3]最开始不知道,所以dp[3][1]不知道,所以dp[3][2]不知道,但是最后有dp[3][3];
所以联立这3个方程可解出dp[3][3],然后求dp[3][1],dp[3][2]...
见代码注释部分:
注意特判一种情况。就是p4<eps时候,就不会崩溃了,应该直接输出0
*/
double
dp[Maxn][Maxn];
double
p1,p2,p3,p4,temp[Maxn];
double
pp[Maxn];
int
n,m,k;
int
main()
{
double
pp2,pp3,pp4;
while
(~
scanf
(
"%d%d%d"
,&n,&m,&k))
{
scanf
(
"%lf%lf%lf%lf"
,&p1,&p2,&p3,&p4);
if
(p4<=eps)
{
puts
(
"0.00000"
);
continue
;
}
pp2=p2/(1-p1);pp3=p3/(1-p1);
pp4=p4/(1-p1);
pp[0]=1.0;
for
(
int
i=1;i<=n;i++)
pp[i]=pp[i-1]*pp2;
dp[1][1]=p4/(1-p1-p2);
for
(
int
i=2;i<=n;i++)
{
temp[1]=pp4;
for
(
int
j=2;j<=k;j++)
temp[j]=pp3*dp[i-1][j-1]+pp4;
for
(
int
j=k+1;j<=i;j++)
temp[j]=pp3*dp[i-1][j-1];
double
tmp=0.0;
for
(
int
j=i;j>=1;j--)
tmp+=temp[j]*pp[i-j];
dp[i][i]=tmp/(1-pp[i]);
dp[i][1]=pp2*dp[i][i]+temp[1];
for
(
int
j=2;j<i;j++)
dp[i][j]=pp2*dp[i][j-1]+temp[j];
}
printf
(
"%0.5f\n"
,dp[n][m]);
}
return
0;
}