概率dpACM-ICPC 2017 Asia Urumqi:A. Coins

                                                            Coins I

                                                             时间限制: 1 Sec  内存限制: 128 MB
                                                                        提交: 101  解决: 60
                                                           [提交] [状态] [讨论版] [命题人: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

题意:有n枚朝下的硬币,我们可以投掷这些硬币m次,每次投掷 t 枚硬币,问最后朝上硬币的期望

答安就是有0到n枚硬币朝上,每种情况的概率*相应情况的加和,0*概率[0]+1*概率[1]+...

dp[i][j]代表前i次投掷正面向上的个数为j的概率

代码:

#include<bits/stdc++.h>
using namespace std;
double c[103][103],p[103],dp[103][103];
int main()
{
    int n,m,k;
    int  t; c[0][0]=1;
    for(int i=1; i<=100; i++)
    {
        c[i][0]=1;
        for(int j=1; j<=i; j++)
        {
            c[i][j]=c[i-1][j-1]+c[i-1][j];
        }
    }
    p[0]=1;
    for(int i=1; i<=100; i++)
    {
        p[i]=p[i-1]/2.0;
    }
   
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&m,&k);
        memset(dp,0,sizeof(dp));
        dp[1][0]=1;
        for(int i=1; i<=m+1; i++)
        {
            for(int j=0; j<=n; j++)
            {
                for(int l=0; l<=k; l++)//下次投掷会增加的数量
                {
                    if(n-j>=k)//剩余反面的硬币数大于等于k个
                    {
                        dp[i+1][j+l]+=dp[i][j]*c[k][l]*p[k];
                    }
                    else
                    {
                        dp[i+1][j-(k-(n-j))+l]+=dp[i][j]*c[k][l]*p[k];
                     //剩余反面个数小于k个,那就将状态转移给在原来j个正面的基础上减去已经是正面的个数,因为此时才是可以下一次投掷增加l个也就是0-k个
                    }
                }
            }
        }
        double ans=0;
        for(int i=1; i<=n; i++)
        {
            ans+=dp[m+1][i]*(i*1.0);//将相应概率和相应情况相乘
        }
        printf("%.3f\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/wrwhahah/article/details/81941466