Coins(概率dp)

Coins I

题目描述

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

题目思路

每次选k个中t个为正面的概率为c(k,t)*0.5^k,所以需要预处理一下100以内的组合数,否则会超时。

以操作次数作为阶段,有几个硬币为正面作为状态,dp[i][j]表示i次操作后正面个数为j的概率。

这里注意,如果j<=n-k,因为取最优策略,所以不会有正面硬币被选来抛。

反之有可能有正面硬币被抛为反面,所以当j超过n-k时,不管j超过多少,硬币为正面的个数都为n-k加上本次抛的为正面的个数,因为原来为正面的也需要重新抛。

所以状态的转移如下

if(j<=n-k)
  dp[i][j+t]+= dp[i-1][j]*p*c[k][t];
else
  dp[i][n-k+t]+= dp[i-1][j]*p*c[k][t];

 最后的答案为n次操作后硬币正面的个数乘以它的概率相加。

代码如下

#include<bits/stdc++.h>
#define ll long long
#define mod 1000000007
using namespace std;
int t,n,m,k;
double dp[110][110],p,c[101][101];
int main()
{
    for (int i=0;i<=100;i++)
        for (int j=0;j<=i;j++)
            if (j==0||i==j) 
                c[i][j]=1;
            else 
                c[i][j]=c[i-1][j-1]+c[i-1][j];
    cin>>t;
    while(t--)
    {
        scanf("%d%d%d",&n,&m,&k);
        memset(dp,0,sizeof(dp));
        dp[0][0] = 1;
        p = pow(0.5,k);
        for(int i = 1;i<=m;i++)//阶段 
            for(int j = 0;j<=n;j++)//状态
                for(int t = 0;t<=k;t++)
                    if(j<=n-k)
                        dp[i][j+t]+= dp[i-1][j]*p*c[k][t];
                    else
                        dp[i][n-k+t]+= dp[i-1][j]*p*c[k][t];
        double ans = 0;
        for(int i = 1;i<=n;i++)
            ans+=dp[m][i]*i;
        printf("%.3lf\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/loganacmer/p/11321686.html