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

样例输出

扫描二维码关注公众号,回复: 3972953 查看本文章
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 次翻转,会遇到两种情况:

  1. j+k<=n: 即我们可以选k个反面朝上的硬币操作,然后可以求得这k个硬币中朝上的个数 t 的概率p,那么dp[i+1][j+t] = dp[i][j]*p;    p = C(k,t)* (1/2)^k
  2. 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;
}
  

猜你喜欢

转载自blog.csdn.net/dong_qian/article/details/82666892
今日推荐