upc 5212: Coins I (概率dp)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/winter2121/article/details/81941455

5212: Coins I

时间限制: 1 Sec  内存限制: 128 MB
提交: 100  解决: 59
[提交] [状态] [讨论版] [命题人:admin]

题目描述

Alice and Bob are playing a simple game. They line up a row of n identical coins, all with the heads facing down onto the table and the tails upward.
For exactly m times they select any k of the coins and toss them into the air, replacing each of them either heads-up or heads-down with the same possibility. Their purpose is to gain as many coins heads-up as they can.

输入

The input has several test cases and the first line contains the integer t (1 ≤ t ≤ 1000) which is the total number of cases.
For each case, a line contains three space-separated integers n, m (1 ≤ n, m ≤ 100) and k (1 ≤ k ≤ n).

输出

For each test case, output the expected number of coins heads-up which you could have at the end under the optimal strategy, as a real number with the precision of 3 digits.

样例输入

6
2 1 1
2 3 1
5 4 3
6 2 3
6 100 1
6 100 2

样例输出

0.500
1.250
3.479
3.000
5.500
5.000

来源/分类

ICPC2017  Urumqi 

[提交] [状态]

【题意】

桌面上有n个硬币全部反着,现在你有m次操作机会,每次可以任选k个,然后抛向空中,每个落下来有0.5的概率正,0.5反。

问,在尽量使硬币为正的策略下,最后的正面期望值。

【分析】

dp[i][j]表示第i次操作,正面朝上的有j个的概率。

枚举次数,枚举正面数,枚举本次要把几个抛正。

【代码】

#include<bits/stdc++.h>
using namespace std;

double two[120];
double C[110][110];
double dp[110][110];
int main()
{
    C[0][0]=1;//特殊
    for(int i=1;i<105;i++)
        for(int j=0;j<=i;j++)
            C[i][j]=(j == 0) ? 1:(C[i-1][j]+C[i-1][j-1]);

    two[0]=1.0;
    for(int i=1;i<=100;i++) two[i]=two[i-1]*0.5;

    int T,n,m,k;
    cin>>T;
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&k);
        for(int i=0;i<=m;i++)
            for(int j=0;j<=n;j++)
                dp[i][j]=0;
        dp[0][0]=1.0;
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<=n;j++) //枚举up
            {
                for(int x=0;x<=k;x++) //枚举我要反过来x个,最多k个
                {
                    double p=C[k][x]*two[k];//从k个中选x个抛成正的概率
                    if(n-j>=k) //直接反所有down的
                        dp[i+1][j+x]+=dp[i][j]*p;
                    else
                        dp[i+1][n-k+x]+=dp[i][j]*p; //反的全选,再选一部分正的,用原来正n-k加上现在弄正的x个0
                }
            }
        }
        double ans=0;
        for(int i=0;i<=n;i++)
            ans+=dp[m][i]*i;
        printf("%.3f\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/winter2121/article/details/81941455