问题 A: Coins I

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

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

概率dp,唉,丢人,做题还是少;

用dp[i][j]表示翻第i轮,有j个朝上,这题用往后推的方法比较好写。而不是在前面找。
然后用C[i][j]表示抛i个硬币,有j个向上的概率,注意这个概率跟那i个硬币原来是正是反没关系。
根据题目的要求,要尽量让向上的硬币多,所以每次尽量选朝下的硬币,但朝下的硬币可能不够,所以
dp里往后推的时候要分两种情况
1. 朝下硬币够k个
2. 朝下硬币不够,要从朝上硬币里面借,因为它们本来就是朝上的,所以这次朝上硬币增加的数量要减少(k-n+j)个

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
double dp[105][105];
double c[105][105];
double p[105];
int main()
{
    int t;
    scanf("%d",&t);
    for(int i=1; i<=105; i++)
    {
        c[i][0]=1.0;
        for(int j=1; j<=105; j++)
        {
            if(i==j)
            {
                c[i][j]=1.0;
            }
            else
            {
                c[i][j]=c[i-1][j-1]+c[i-1][j];
            }
        }
    }
    p[0]=1;
    for(int i=1;i<=105;i++)
    {
        p[i]=p[i-1]/2.0;
    }

    while(t--)
    {
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
        memset(dp,0,sizeof(dp));
        dp[0][0]=1.0;
        for(int i=0; i<=m; i++)
        {
            for(int j=0; j<=n; j++)
            {
                if(dp[i][j]==0)
                    continue;
                for(int l=0; l<=k; l++)
                {
                    if(n-j>=k)
                    {
                        dp[i+1][j+l]+=dp[i][j]*c[k][l]*p[k];
                    }
                    else
                    {
                        dp[i+1][(j+l)-(k-(n-j))]+=dp[i][j]*c[k][l]*p[k];
                    }
                }
            }
        }

        double ans = 0;

        for (int i=1;i<=n;i++) ans += 1.0 * i * dp[m][i];

        printf("%.3f\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/wuxiaowu547/article/details/81913809
今日推荐