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次,每次都选择k枚硬币抛起,每一枚硬币正面向上的概率是0.5
尽可能的使正面朝上,问经过m次操作之后,正面朝上的期望值
分析:首先,最优策略就是:每次选取k个的时候,我们先选反面朝上的硬币,如果不够,再选正面朝上的
因为每次的翻转只跟上次的翻转情况有关,所以我们可以推导一下递推式dp
很容易想到dp[i][j] 表示 翻转完第i次时,j个硬币正面朝上的概率
递推式:我们得到了dp[i][j] 第 i 次翻转后有 j 个正面朝上,这时候我们进行第 i+1 次翻转,会遇到两种情况:
- j+k<=n: 即我们可以选k个反面朝上的硬币操作,然后可以求得这k个硬币中朝上的个数 t 的概率p,那么dp[i+1][j+t] = dp[i][j]*p; p = C(k,t)* (1/2)^k
- j+k > n: 即需要选择 tp=(j+k-n) 个正面朝上的硬币进行翻转,所以第i+1次翻转后确定的正面朝上的个数为 j-tp 个,然后考虑k个刚翻转的正面朝上的个数t 的概率p,p还是C(k,t)* (1/2)^k;所以此时递推式为 dp[i+1][j-tp+t] = dp[i][j]*p;
而且:对于给定的k,t 的概率p恒为 C(k,t)* (1/2)^k,所以可以先预处理这一部分
代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
double maze[120];
double panduan[110][110],ff[110][110];
void inti()
{
memset(maze,0,sizeof(maze));
maze[0]=1.0;
for(int i=1;i<=100;i++)
maze[i]=maze[i-1]/2.0;
memset(panduan,0,sizeof(panduan));
panduan[0][0]=1.0;
for(int i=1;i<105;i++){
for(int j=0;j<=i;j++){
if(j==0)
panduan[i][j]=1;
else
panduan[i][j]=panduan[i-1][j]+panduan[i-1][j-1];
}
}
return ;
}
double sum;
int f,n,m,k;
void jinxing()
{
for(int i=0;i<m;i++){
for(int j=0;j<=n;j++){
for(int u=0;u<=k;u++){
double p=panduan[k][u]*maze[k];
if(n-j>=k)
ff[i+1][j+u]+=ff[i][j]*p;
else
ff[i+1][n-k+u]+=ff[i][j]*p;
// printf("%d %d %d %d**\n",i,j,u,k);
}
}
}
return ;
}
int main()
{
inti();
scanf("%d",&f);
while(f--){
scanf("%d %d %d",&n,&m,&k);
memset(ff,0,sizeof(ff));
ff[0][0]=1.0;
jinxing();
/*for(int i=0;i<=n;i++)
printf("%.3lf&& ",ff[m][i]);
printf("\n"); */
sum=0;
for(int i=1;i<=n;i++)
sum+=(double)(ff[m][i]*i);
printf("%.3f\n",sum);
}
return 0;
}