Problem F Flipping Coins(dp)

12 篇文章 0 订阅

Problem FFlipping Coins

Here’s a jolly and simple game: line up a row of N identical coins, all with the heads facingdown onto the table and the tails upwards, and for exactly K times take one of the coins, toss itinto the air, and replace it as it lands either heads-up or heads-down. You may keep all of thecoins that are face-up by the end.

Being, as we established last year, a ruthless capitalist, you have resolved to play optimally towin as many coins as you can. Across all possible combinations of strategies and results, whatis the maximum expected (mean average) amount you can win by playing optimally?

Input

• One line containing two space-separated integers:

– N (1 ≤ N ≤ 400), the number of coins at your mercy;

– K (1 ≤ K ≤ 400), the number of flips you must perform.

Output

Output the expected number of heads you could have at the end, as a real number. The outputmust be accurate to an absolute or relative error of at most 10−6.


题意:

n个数全部反面朝上,k次翻转。

求k次翻转后正面朝上的数学期望。

数学期望(mean)(或均值,亦简称期望)是试验中每次可能结果的概率乘以其结果的总和,是最基本的数学特征之一。

思路:

由于是求最大数学期望,所以每次抛硬币即要优先选择反面硬币

所以只有两种挑选硬币的情况:

  1.正面数量为 0 ~ n-1 ,选择反面硬币抛,抛出结果正面数量比原本 +1 或 不变

  2.正面数量为 n,只能够选择正面硬币抛,抛出结果正面数量比原本 -1 或 不变
-----------------------------------------------------------------------------------------------------------------

设 dp[i][j] 表示: 第 i 次抛硬币后, j 个硬币正面朝上的概率

  1.当 j < n 时,dp[i][j]的概率一分为二,各给dp[i+1][j]dp[i+1][j+1],即

for(int j=0;j<n;j++){
    dp[i+1][j]+=dp[i][j]/2;
    dp[i+1][j+1]+=dp[i][j]/2;
}

  2.当 j == n 时,dp[i][j]的概率一分为二,各给dp[i+1][j]dp[i+1][j-1],即

dp[i+1][n]+=dp[i][n]/2;
dp[i+1][n-1]+=dp[i][n]/2;

如此即可求出n个硬币抛k次的各个正面朝上的概率,最后求数学期望即可


代码:

#include<iostream>
#include<cstring>
#include<iomanip>
using namespace std;

double dp[405][405];  //第i次j个正面朝上的期望

int main()
{
    int n,k;
    cin>>n>>k;
    memset(dp,0,sizeof(dp));
    dp[0][0]=1;
    for(int i=0;i<k;i++)
    {
        for(int j=0;j<n;j++)  //0-n个正面情况(两种情况,+1,不变)。每次翻反面
        {
            dp[i+1][j]+=dp[i][j]*0.5;  //不能/2,会舍小数
            dp[i+1][j+1]+=dp[i][j]*0.5;
        }
        dp[i+1][n]+=dp[i][n]*0.5;  //n个正面(-1,不变)
        dp[i+1][n-1]+=dp[i][n]*0.5;
    }
    double sum=0;
    for(int i=1;i<=n;i++)
    {
        sum+=i*dp[k][i];
    }
    cout<<fixed<<setprecision(6)<<sum<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值