ACM-ICPC 2017 Asia Urumqi A. Coins【期望dp】

题目链接:https://www.jisuanke.com/contest/2870?view=challenges

题目大意:给出n个都正面朝下的硬币,操作m次,每次都选取k枚硬币抛到空中,求操作m次后,硬币向上的期望值。

思路:

1.期望跟概率还是有点不同的,期望要枚举出抛的所有的情况,然后求sigma(i * dp[][])

2.dp[i][j]表示进行i次操作后,有j枚硬币向上的概率。这样就可以求最后的硬币向上的期望了。

3.值得注意的是,预处理的组合数要开 double 型。

代码:

 1 #include<stdio.h>
 2 #include<string.h>
 3 #define mem(a, b) memset(a, b, sizeof(a))
 4 
 5 double C[110][110];//组合数
 6 double P[110]; //翻i个硬币的概率,因为正反都是 1 / 2,所以用一维数组表示
 7 double dp[110][110]; //表示操作i次,有j枚硬币正面向上的概率 
 8 int n, m, k;
 9 
10 int main()
11 {
12     //预处理组合数
13     C[0][0] = 1;
14     for(int i = 1; i <= 100; i ++)
15     {
16         C[i][0] =  1;
17         for(int j = 1; j <= i; j ++)
18         {
19             C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
20         }
21     }
22     //预处理i个硬币的概率 
23     P[0] = 1.0;
24     for(int i = 1; i <= 100; i ++)
25         P[i] = 0.5 * P[i - 1];
26     int T;
27     scanf("%d", &T);
28     while(T --)
29     {
30         mem(dp, 0);
31         dp[0][0] = 1.0;
32         scanf("%d%d%d", &n, &m, &k);
33         for(int i = 0; i < m; i ++)//枚举操作次数 
34         {
35             for(int j = 0; j <= n; j ++)//枚举硬币正面向上的个数 
36             {
37                 if(dp[i][j] == 0)
38                     continue;
39                 for(int q = 0; q <= k; q ++)//枚举抛k枚硬币有多少枚硬币会朝上,枚举所有情况,才是求期望 
40                 {
41                     if((n - j) >= k)
42                         dp[i + 1][j + q] += dp[i][j] * C[k][q] * P[k];
43                     else
44                         dp[i + 1][j + q - (k - (n - j))] += dp[i][j] * C[k][q] * P[k];
45                 }
46             }
47         }
48         double ans = 0.0;
49         for(int i = 0; i <= n; i ++)
50         {
51             ans += dp[m][i] * i;
52         }
53         printf("%.3lf\n", ans);
54     }
55     return 0;
56 }
View Code

猜你喜欢

转载自www.cnblogs.com/yuanweidao/p/10992250.html