HDU 4089 Activation(概率dp)

Activation

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4222    Accepted Submission(s): 1411

Problem Description

After 4 years' waiting, the game "Chinese Paladin 5" finally comes out. Tomato is a crazy fan, and luckily he got the first release. Now he is at home, ready to begin his journey.
But before starting the game, he must first activate the product on the official site. There are too many passionate fans that the activation server cannot deal with all the requests at the same time, so all the players must wait in queue. Each time, the server deals with the request of the first player in the queue, and the result may be one of the following, each has a probability:
1. Activation failed: This happens with the probability of p1. The queue remains unchanged and the server will try to deal with the same request the next time.
2. Connection failed: This happens with the probability of p2. Something just happened and the first player in queue lost his connection with the server. The server will then remove his request from the queue. After that, the player will immediately connect to the server again and starts queuing at the tail of the queue.
3. Activation succeeded: This happens with the probability of p3. Congratulations, the player will leave the queue and enjoy the game himself.
4. Service unavailable: This happens with the probability of p4. Something just happened and the server is down. The website must shutdown the server at once. All the requests that are still in the queue will never be dealt.
Tomato thinks it sucks if the server is down while he is still waiting in the queue and there are no more than K-1 guys before him. And he wants to know the probability that this ugly thing happens.
To make it clear, we say three things may happen to Tomato: he succeeded activating the game; the server is down while he is in the queue and there are no more than K-1 guys before him; the server is down while he is in the queue and there are at least K guys before him.
Now you are to calculate the probability of the second thing.

Input

There are no more than 40 test cases. Each case in one line, contains three integers and four real numbers: N, M (1 <= M <= N <= 2000), K (K >= 1), p1, p2, p3, p4 (0 <= p1, p2, p3, p4 <= 1, p1 + p2 + p3 + p4 = 1), indicating there are N guys in the queue (the positions are numbered from 1 to N), and at the beginning Tomato is at the Mth position, with the probability p1, p2, p3, p4 mentioned above.

Output

A real number in one line for each case, the probability that the ugly thing happens.
The answer should be rounded to 5 digits after the decimal point.

Sample Input

 

 

2 2 1 0.1 0.2 0.3 0.4 3 2 1 0.4 0.3 0.2 0.1 4 2 3 0.16 0.16 0.16 0.52

 

Sample Output

 

 

0.30427 0.23280 0.90343

Source

2011 Asia Beijing Regional Contest 

 

 

        大致题意是,给你一个注册激活序列,告诉你人数,每个时刻可能会发生四种事情。1、队首的人注册激活失败,下一个时刻这个人继续尝试激活。2、队首的人连接中断,直接从队首出队跳到队尾。3、注册激活成功,队首出队。4、服务器崩溃,所有的请求终止。最后告诉你你现在在队列中的位置,当你前面的人少于k的时候,服务器崩溃的概率是多少。

        考虑概率dp,从前往后正着推。定义dp[i][j]表示总共有i个人,我排在第j位的时候,达到目标状态的概率(j<=k)。那么有转移方程:

 

               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)

        可以看到,当2<=j<=k的时候,dp[i][j]是可以从前面推出来的,但是我们看到,dp[i][1]和dp[i][i]却出现了循环的情况,即要求你就要求我,要求我就要求你。正常来说,对于这种问题,我们可以看作一个方程组,可以用高斯消元取求解,但是这里看到数据范围可以到2K,用高斯消元不实际。幸运的是,我们这里可以手动消元,我们发现,每一个dp[i][j]与前一项有关,那么我们可以直接把前一项的表达式代入。代入之后又可以继续代入,一直迭代下去,知道代入dp[i][1]的表达式。这时,我们发现,等式两边就只剩下了dp[i][i]这一个未知数。直接求解出来即可。

        更加具体的说,对于表达式所有的表达式,我们都可以写成dp[i][j]=p1*dp[i][j-1]+c[j]的形式,不断迭代到最后一步,我们可以有dp[i][i]=Σp1^(i-j)*c[j]+c[i]+p2*dp[i][i]。如此就可以手动的先求出dp[i][i],然后顺带求出dp[i][1],最后从2到i-1依次求dp[i][j]即可。然后,由于这题还卡你的空间,所以用上滚动数组。具体见代码:

#include<bits/stdc++.h>
#define DB double
#define eps 1e-5
#define N 1010

using namespace std;

DB dp[2][N],p1,p2,p3,p4,p2p[N],c[N];
int m,n,k;

int main()
{
    while(~scanf("%d%d%d%lf%lf%lf%lf",&n,&m,&k,&p1,&p2,&p3,&p4))
    {
        bool cur=1,pre=0;
        memset(dp,0,sizeof(dp));
        if (fabs(p4)<eps) {puts("0.00000");continue;}
        DB p=1.-p1,p41=p4/p,p31=p3/p;
        dp[cur][1]=p4/(p-p2);
        p2p[0]=1.; DB pp=p2/p; c[1]=p41;
        for(int i=1;i<=n;i++)
            p2p[i]=p2p[i-1]*pp;
        for(int i=2;i<=n;i++)
        {
            cur^=1; pre^=1;
            DB s=c[1]*p2p[i-1];
            for(int j=2;j<=k&&j<=i;j++)
                c[j]=p31*dp[pre][j-1]+p41;
            for(int j=k+1;j<=i;j++)
                c[j]=p31*dp[pre][j-1];
            for(int j=2;j<=i;j++) s+=p2p[i-j]*c[j];
            dp[cur][i]=s/(1.-p2p[i]);
            dp[cur][1]=p41+pp*dp[cur][i];
            for(int j=2;j<i;j++)
                dp[cur][j]=pp*dp[cur][j-1]+c[j];
            memset(dp[pre],0,sizeof(dp[pre]));
        }
        printf("%.5f\n",dp[cur][m]);
    }
    return 0;
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值