Coins (永远不可能学会的动态规划之概率DP)

                                                  Coins

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

                                                                            [提交]       [状态]

题意:

扫描二维码关注公众号,回复: 2944483 查看本文章

一开始有 n 枚硬币反面朝上,有 m 次机会,每次机会必须选取 k 枚硬币上抛,问在最优策略下,最后能有多少枚硬币正面朝上。

题解:

借鉴的大神的思路

用dp[i][j]表示第i次上抛结束后j枚硬币朝上的概率;

首先最优策略是第 i 次上抛结束后有 j 枚硬币一定正面朝上,则第i+1次选取k枚硬币时

1.如果 j + k <= n,也就是此时反面朝上的硬币数量 >= k,那么我们此时肯定要从反面朝上的硬币中选,dp[i+1][j+t]就表示第i+1次结束以后,j+t枚硬币正面朝上的概率,dp[i+1][j+t] += dp[i][j] * C(k,t)  /  (2^k);

2.如果j + k > n,也就是反面朝上的硬币数量 <k,令 tt = j + k - n,也就是说要从已经正面朝上的硬币中选取tt枚硬币上抛,从反面朝上的硬币中选取k - tt枚硬币上抛,则i+1次上抛硬币结束后一定正面朝上的硬币数量为 j - tt,因此i+1次后,dp[i+1][j - tt + t] = dp[i][j] * C(k,t)  /  (2^k);

PS 概率DP中数学期望 P=Σ每一种状态*对应的概率

正常的DP代码是逆向推的,而这个是正向推的,更好理解

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
#include<vector>
#include<stdlib.h>
#include<math.h>
#include<queue>
#include<deque>
#include<ctype.h>
#include<map>
#include<set>
#include<stack>
#include<string>
#define INF 0x3f3f3f3f
#define FAST_IO ios::sync_with_stdio(false)
const double PI = acos(-1.0);
const double eps = 1e-6;
const int MAX=1e6+10;
const int mod=1e9+7;
typedef long long ll;
using namespace std;
#define gcd(a,b) __gcd(a,b)
inline ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
inline ll qpow(ll a,ll b){ll r=1,t=a; while(b){if(b&1)r=(r*t)%mod;b>>=1;t=(t*t)%mod;}return r;}
inline ll inv1(ll b){return qpow(b,mod-2);}
inline ll exgcd(ll a,ll b,ll &x,ll &y){if(!b){x=1;y=0;return a;}ll r=exgcd(b,a%b,y,x);y-=(a/b)*x;return r;}
inline ll read(){ll x=0,f=1;char c=getchar();for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;for(;isdigit(c);c=getchar()) x=x*10+c-'0';return x*f;}
//freopen( "in.txt" , "r" , stdin );
//freopen( "data.txt" , "w" , stdout );
const ll maxn = 105;
double dp[maxn][maxn];
double c[maxn][maxn];
int n,m,k;
void init()
{
    double temp=1.0;
    for(int i=1;i<=k;i++)temp*=2.0;
    c[k][0]=1;
    for(int i=1;i<=k;i++)c[k][i]=c[k][i-1]*(k-i+1)/i;
    for(int i=0;i<=k;i++)
        c[k][i]/=temp;

}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&m,&k);
        init();
        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(j+k<=n)
                {
                    for(int t=0;t<=k;t++)
                        dp[i+1][j+t]+=dp[i][j]*c[k][t];
                }
                else
                {
                    int tt=j+k-n;
                    for(int t=0;t<=k;t++)
                        dp[i+1][j+t-tt]+=dp[i][j]*c[k][t];
                }
            }
        }
        double ans=0.0;
        for(int i=0;i<=n;i++)
            ans+=i*dp[m][i];
        printf("%.3f\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_41021816/article/details/81944590