Gym 101606F Flipping Coins [ 递推 DP ]

Gym 101606F Flipping Coins [ 递推 DP ]_第1张图片

Gym 101606F Flipping Coins [ 递推 DP ]_第2张图片

题意:有n个硬币,排成一排,抛k次,一开始都是反面朝上,问正面朝上硬币的期望。

思路:全程懵逼啊。。。。。

----------------------------------------------------------------------------------------------------------------------

随机变量X是指正面朝上的硬币的个数, 概率为p(X); X = 0, 1, 2, 3, 4, ......, n;

E(X) = 1*p(1) +2*p(2) + 3*p(3)+....+n*p(n);

要想求最大期望,我们在扔硬币的时候最好是尽量扔正面朝下的硬币;  

如果当前有0到n - 1枚硬币正面朝上,我们可以选择正面朝下的硬币来扔,扔完以后朝上的硬币数不变或者+1;

如果当前有n枚硬币正面朝上,我们只能选择正面朝上的硬币来扔,扔完以后朝上的硬币数不变或者-1;

 ---------------------------------------------------------------------------------------------------------------------

令dp[ i ][ j ]为扔i次以后 j枚硬币朝上的概率;

根据上面总结的规律,我们可以得到的状态转移方程:

当 j < n 时: 

                    dp[i + 1][ j ] += dp[ i ][ j ]*0.5

                    dp[i + 1][ j + 1] += dp[ i ][ j ]*0.5

当j = n 时:

                    dp[i + 1][ j + 1] += dp[ i ][ j ]*0.5

                    dp[i + 1][ j  - 1] += dp[ i ][ j ]*0.5

这样递推出概率来以后遍历一遍 j 求期望就可以了。。

代码:

#include
#define ll long long
using namespace std;

const int N=400+10;
int n, k;
double dp[N][N], ans = 0;

int main(){
    //freopen("in.txt","r",stdin);
    while(~scanf("%d%d", &n,&k))
    {
        ans = 0;
        memset(dp, 0, sizeof(dp)); dp[0][0] = 1.0;
        for(int i = 0; i < k; i++)
        {
            for(int j = 0; j < n; j++)
                dp[i+1][j] += dp[i][j]*0.5,    //j < n扔完以后朝上的硬币数不变;
                dp[i+1][j+1] += dp[i][j]*0.5;  //j < n扔完以后朝上的硬币数 +1;
            dp[i + 1][n] += dp[i][n]*0.5;      //j = n扔完以后朝上的硬币数不变;
            dp[i + 1][n - 1] += dp[i][n]*0.5;  //j = n扔完以后朝上的硬币数 -1;
        }
        for(int i=1;i<=n;i++) ans += dp[k][i]*i; //E(X) = 1*P(1) + 2*p(2)+...+n*P(n);
        printf("%.6lf\n", ans);
    }
    return 0;
}


你可能感兴趣的:(动态规划,GYM)