//dp[i][state]
//状态转移方程的选取:题目的意思是,从点 i 优先考虑到达 i + A 点的情况,若不能到达 i + A 点,则考虑到达 i + A + 1 点的情况...以此类推,直到考虑完到达 i + B 点的情况。对于最坏的情况,每一个点都有 B - A + 1 个后继点,所以由前向后推比较合适。
//题目是要求当走到 [1...n] 中的某一点不能继续走的时候 或者 走到超出 n 点的位置时的总步数期望,因为在 [1...n] 中的任意一点都可能不能继续走,超出 n 点的位置也有可能有很多(namely 状态终点非常多,而且一般计算期望的方式是状态终点置零,从后往前推),所以我们换个方式思考这个问题。注意到 到达 [i, state] 的概率 * 1,其实就是从[i, state] 的前驱状态到达 [i, state] 的步数期望,将这些 1 步的期望全部加起来,就是题目要求的总步数期望
1 #include "iostream" 2 #include "cstdio" 3 #include "cstring" 4 #include "algorithm" 5 #include "cmath" 6 using namespace std; 7 const double eps = 1e-10; 8 double dp[4010][4], p[4010][4]; 9 int n, A, B; 10 11 int main() 12 { 13 int T, i, j; 14 scanf("%d", &T); 15 while(T--) { 16 scanf("%d%d%d", &n, &A, &B); 17 for(i = 1; i <= n; ++i) 18 for(j = 0; j <= 3; ++j) 19 scanf("%lf", &p[i][j]); 20 for(i = n + 1; i <= n + A; ++i) 21 for(j = 0; j <= 3; ++j) 22 p[i][j] = (j == 3); 23 memset(dp, 0, sizeof(dp)); 24 dp[0][3] = 1; 25 for(i = 0; i <= n; ++i) { 26 double p1, p2, p3; 27 p1 = p2 = p3 = 1; 28 for(j = i + A; j <= i + B; ++j) { 29 if(j > n + A) 30 break; 31 dp[j][2] += dp[i][1] * p1 * p[j][2]; 32 dp[j][3] += dp[i][1] * p1 * p[j][3]; 33 p1 *= (p[j][0] + p[j][1]); 34 dp[j][1] += dp[i][2] * p2 * p[j][1]; 35 dp[j][3] += dp[i][2] * p2 * p[j][3]; 36 p2 *= (p[j][0] + p[j][2]); 37 dp[j][1] += dp[i][3] * p3 * p[j][1]; 38 dp[j][2] += dp[i][3] * p3 * p[j][2]; 39 dp[j][3] += dp[i][3] * p3 * p[j][3]; 40 p3 *= p[j][0]; 41 } 42 } 43 double res = 0; 44 for(i = 1; i <= n + A; ++i) 45 for(j = 1; j <= 3; ++j) 46 res += dp[i][j]; 47 printf("%.8f ", res); 48 } 49 }
//附上一种等价的写法
1 #include "iostream" 2 #include "cstdio" 3 #include "cstring" 4 #include "algorithm" 5 #include "cmath" 6 using namespace std; 7 const double eps = 1e-10; 8 double dp[4010][4], p[4010][4]; 9 int n, A, B; 10 11 int main() 12 { 13 int T, i, j; 14 scanf("%d", &T); 15 while(T--) { 16 scanf("%d%d%d", &n, &A, &B); 17 for(i = 1; i <= n; ++i) 18 for(j = 0; j <= 3; ++j) 19 scanf("%lf", &p[i][j]); 20 for(i = n + 1; i <= n + A; ++i) 21 for(j = 0; j <= 3; ++j) 22 p[i][j] = (j == 3); 23 memset(dp, 0, sizeof(dp)); 24 dp[0][3] = 1; 25 double res = 0; 26 for(i = 0; i <= n; ++i) { 27 double p1, p2, p3; 28 p1 = p2 = p3 = 1; 29 for(j = i + A; j <= i + B; ++j) { 30 if(j > n + A) 31 break; 32 res += dp[i][1] * p1 * p[j][2] + dp[i][1] * p1 * p[j][3] + dp[i][2] * p2 * p[j][1] + dp[i][2] * p2 * p[j][3] + dp[i][3] * p3 * p[j][1] + dp[i][3] * p3 * p[j][2] + dp[i][3] * p3 * p[j][3]; 33 dp[j][2] += dp[i][1] * p1 * p[j][2]; 34 dp[j][3] += dp[i][1] * p1 * p[j][3]; 35 p1 *= (p[j][0] + p[j][1]); 36 dp[j][1] += dp[i][2] * p2 * p[j][1]; 37 dp[j][3] += dp[i][2] * p2 * p[j][3]; 38 p2 *= (p[j][0] + p[j][2]); 39 dp[j][1] += dp[i][3] * p3 * p[j][1]; 40 dp[j][2] += dp[i][3] * p3 * p[j][2]; 41 dp[j][3] += dp[i][3] * p3 * p[j][3]; 42 p3 *= p[j][0]; 43 } 44 } 45 printf("%.8f ", res); 46 } 47 }