HDU--4089(概率DP)
2015-04-21 22:22:23
题意:一队人排着队激活游戏,服务器每次对队首的人的要求进行处理,有4种可能:
(1)失败,概率p1 (2)失联,排到队末,概率p2 (2)成功,概率p3 (4)服务器崩溃,概率p4
一开始一队有n个人,某人排在第m个,问服务器崩溃时该人前面的人数 <= k-1 的概率。
思路:
一开始完全木有思路... TAT,看了博客~
好一道概率DP,还卡了空间... 必须用滚动数组优化一下。
首先,dp数组的定义很重要,dp[i][j]表示一队共 i 个人,该人排在第 j 个时到达目标状态的概率。
列出方程:
j == 1 : dp[i][1] = dp[i][1]*p1 + dp[i][i]*p2 + p4
2<=j<=k: dp[i][j] = dp[i][j]*p1 + dp[i][j-1]*p2 + dp[i-1][j-1]*p3 + p4;
k<j<=i: dp[i][j] = dp[i][j]*p1 + dp[i][j-1]*p2 + dp[i-1][j-1]*p3
令 : P2 = p2/(1-p1) , P3 = p3/(1-p1) , P4 = p4/(1-p1),转化方程为:
j == 1 : dp[i][1] = dp[i][i]*P2 + P4
2<=j<=k: dp[i][j] = dp[i][j-1]*P2 + dp[i-1][j-1]*P3 + P4;
k<j<=i: dp[i][j] = dp[i][j-1]*P2 + dp[i-1][j-1]*P3
※我们发现,每层循环首先要求出dp[i][1],我们可以循环迭代一下得到下列方程:
注意:如果p4==0或者p1==1,答案显然0
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=0;i<(n);++i) 17 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 18 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 19 #define MP(a,b) make_pair(a,b) 20 21 typedef long long ll; 22 typedef pair<int,int> pii; 23 const int INF = (1 << 30) - 1; 24 const int MAXN = 2001; 25 const double eps = 1e-4; 26 27 int n,m,k; 28 double p1,p2,p3,p4; 29 double P2,P3,P4; 30 double dp[2][MAXN]; 31 double pw[MAXN]; 32 33 int main(){ 34 while(scanf("%d%d%d%lf%lf%lf%lf",&n,&m,&k,&p1,&p2,&p3,&p4) != EOF){ 35 if(fabs(p4) < eps || fabs(p1 - 1.0) < eps){ 36 printf("0.00000\n"); 37 continue; 38 } 39 P2 = p2 / (1.0 - p1); 40 P3 = p3 / (1.0 - p1); 41 P4 = p4 / (1.0 - p1); 42 pw[0] = 1.0; 43 for(int i = 1; i <= n; ++i) pw[i] = pw[i - 1] * P2; 44 MEM(dp,0); 45 dp[1][1] = P4 / (1.0 - P2); 46 for(int i = 2; i <= n; ++i){ 47 int id = i&1; 48 double cur = 0; 49 for(int j = 1; j <= i - 1; ++j) cur += dp[id^1][j] * pw[i - j] * P3; 50 for(int j = max(1,i - k + 1); j <= i - 1; ++j) cur += P4 * pw[j]; 51 dp[id][1] = (cur + P4) / (1.0 - pw[i]); 52 for(int j = 2; j <= k; ++j) 53 dp[id][j] = dp[id][j - 1] * P2 + dp[id^1][j - 1] * P3 + P4; 54 for(int j = k + 1; j <= i; ++j) 55 dp[id][j] = dp[id][j - 1] * P2 + dp[id^1][j - 1] * P3; 56 } 57 printf("%.5f\n",dp[n&1][m]); 58 } 59 return 0; 60 }