hdu 4050 概率dp

//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\n", 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\n", res);
46     }
47 }

 

posted @ 2015-02-17 16:52  AC_Phoenix  阅读(221)  评论(0编辑  收藏  举报