题目链接
用dp[i][j]表示翻第i轮,有j个朝上,这题用往后推的方法比较好写。而不是在前面找。
然后用san[i][j]表示抛i个硬币,有j个向上的概率,注意这个概率跟那i个硬币原来是正是反没关系。
根据题目的要求,要尽量让向上的硬币多,所以每次尽量选朝下的硬币,但朝下的硬币可能不够,所以
dp里往后推的时候要分两种情况
1. 朝下硬币够k个,那么dp[i][j]*san[k+1][l+1]
2. 朝下硬币不够,要从朝上硬币里面借,因为它们本来就是朝上的,所以这次朝上硬币增加的数量要减少(k-n+j)个,那么dp[i+1][j+l-(k-n+j)] += dp[i][j]*san[k+1][l+1]
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 110;
double dp[MAXN][MAXN];
double san[MAXN][MAXN];
int n,k,m;
int main()
{
san[1][1] =1;
for (int i=2;i<=100;i++)
for (int j=1;j<=100;j++)
san[i][j] = (san[i-1][j] + san[i-1][j-1])/2.0;
int t;
scanf("%d",&t);
while (t--)
{
scanf("%d%d%d",&n,&m,&k);
memset(dp,0,sizeof dp);
dp[0][0]=1;
for (int i=0;i<=m;i++)
{
for (int j=0;j<=n;j++)
{
for (int l=0;l<=k;l++)
{
if ( n-j>=k ) dp[i+1][j+l] += dp[i][j]*san[k+1][l+1];
else dp[i+1][j+l-(k-n+j)] += dp[i][j]*san[k+1][l+1];
}
}
}
double ans = 0;
for (int i=1;i<=n;i++) ans += 1.0 * i * dp[m][i];
printf("%.3f\n",ans);
}
return 0;
}