HDU 4089 Activation(概率dp)
链接: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; }