HDU 4089 Activation(概率dp)

HDU 4089 Activation

链接:https://ac.nowcoder.com/acm/problem/210487 来源:牛客网

题目描述

吉吉国王偶尔会回想起自己的高中时代。在吉吉国王的高中时代,下课后冲向食堂是每个学生的基本操作,但是总得有人失败,为什么不能是我,实际上吉吉国王在打饭这件事上也是失败过很多次,比如没带饭卡,走错窗口,甚至食堂关门。 吉吉国王的高中食堂排队可以看成一个长度为n的队列,一开始吉吉国王站在mmm这个位置上,一般来说,窗口前的第一个人在打饭的时候会发生四种情况。 第一种情况是打饭的时候窗口没人,这个时候要等待一会儿,发生的概率是p1​。 第二种情况是发现自己没带饭卡,这个时候就要回去拿饭卡并且排到了队列的末尾,发生的概率是p2​。(这里认为每个人只有在即将打饭的时候才会去摸饭卡,只有这时才有发现自己没带饭卡的机会。) 第三种情况是打饭成功,这个时候队列的长度减一,发生的概率是p3。 第四种情况是食堂关门,这个时候大家都不能打饭了,发生的概率是p4​。 吉吉国王老倒霉蛋了,经常在食堂关门的时候排在队伍的前面,因此他想知道这样的事件发生的概率。现在你需要告诉吉吉国王在食堂关门时他排在队伍的前k位的概率。

输入描述:
一行七个数表示n,m,k,p1,p2,p3,p4。
输出描述:
输出一个小数表示答案,小数点后保留五位。
输入
4 4 1 0.372818 0.318286 0.220035 0.0888615
输出:
0.15428
备注:
1≤k≤m≤n≤2000
0≤p1,p2,p3,p4≤1,p1+p2+p3+p4=1

思路:

dp[i] [j] :表示队伍人数为i,吉吉国王排在j,此时达到目标的概率。(j<=i)

题目分情况可得出:

• dp[n] [m]就是所求

•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];

最后的情况不加p4因为k<=j的时候关门并不能达到目标状态。

得到式子后,直接2个for递推就会出现问题,因为不知道边界状态,也就是说f[n] [1~k]状态间都有联系,不能一开始就确定他们的值。

所以设dp[i] [j]=a[j] * dp[i] [i] +b[j]。

带入递推式得:

带入j==1可得:

边界就是a[1]=p2/(1-p1) , b[1]=p4/(1-p1) , dp[1] [1]=p4/(1-p1-p2)。

带入2<=j<=k可得:

(1-p1) * dp[i] [j]=p2*(a[j-1] * dp[i] [i]+b[j-1])+p3*dp[i-1] [j-1] +p4。

化成dp[i] [j]=p2/(1-p1)  *  dp[i] [i]   +   p2/(1-p1) * b[j-1]+p3/(1-p1) * dp[i-1] [j-1] +p4/(1-p1)。

推到dp[i][j]的时候dp[i-1][j-1]是已知量,不需要拆。

就得到a[j],b[j]的递推式。

接下来就是for了。

代码:

 

#include<iostream>
#include<algorithm>
#include<fstream>
#include<cstring>
#include<cstdio>
#include<sstream>
#include<vector>
#include<stack>
#include<deque>
#include<cmath>
#include<map>
#include<queue>
#include<bitset>
//#include<hash_map>
#define sd(x) scanf("%d",&x)
#define lsd(x) scanf("%lld",&x)
#define ms(x,y) memset(x,y,sizeof x)
#define fu(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define all(a) a.begin(),a.end()
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
//using namespace __gnu_cxx;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int maxn=2e3+79;
const int mod=1e9+7;
const int INF=1e9+7;
const double pi=acos(-1);
double dp[maxn][maxn],a[maxn],b[maxn];
vector<int> p;
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    //std::ifstream fil;
    //fil.open("t.txt");
    //freopen("C.in","r",stdin);
    int n,m,k;double p1,p2,p3,p4;
    cin>>n>>m>>k>>p1>>p2>>p3>>p4;
    //dp[i][j]=a[j]*dp[i][i]+b[j];(j<=i,排名不超队伍人数)
    //边界状态
    dp[1][1]=p4/(1-p1-p2);
    a[1]=p2/(1-p1),b[1]=p4/(1-p1);
    fu(i,2,n)
    {
        fu(j,2,i)
        {
            a[j]=p2*a[j-1]/(1-p1);
            b[j]=(p2*b[j-1]+p3*dp[i-1][j-1]+(j<=k?p4:0))/(1-p1);
        }
        dp[i][i]=b[i]/(1-a[i]);
        fu(j,1,i) dp[i][j]=a[j]*dp[i][i]+b[j];
    }
    printf("%.5f\n",dp[n][m]);
    return 0;
}

 

posted on 2020-08-29 09:51  Aminers  阅读(196)  评论(0编辑  收藏  举报

导航