Gym - 101606F 抛硬币(概率dp)

题面:

Here’s a jolly and simple game: line up a row of N identical coins, all with the heads facing

down onto the table and the tails upwards, and for exactly K times take one of the coins, toss it

into the air, and replace it as it lands either heads-up or heads-down. You may keep all of the

coins that are face-up by the end.

Being, as we established last year, a ruthless capitalist, you have resolved to play optimally to

win as many coins as you can. Across all possible combinations of strategies and results, what

is the maximum expected (mean average) amount you can win by playing optimally?

Input

One line containing two space-separated integers:

  N(1<=N<=400), the number of coins at your mercy;

  K(1<=K<=400), the number of flips you must perform.

Output

Output the expected number of heads you could have at the end, as a real number. The output

must be accurate to an absolute or relative error of at most 10-6.

Gym - 101606F 抛硬币(概率dp)_第1张图片

题目描述:

 给出N个硬币(N<=400),开始均反面朝上。每次挑出其中一个抛,连续抛K次(K<=400),求正面朝上的最大数学期望。

题目分析:

由于是求最大数学期望,所以每次抛硬币都要选择反面硬币来抛,除非没有反面硬币

所以有两种抛硬币的情况:

  ①.正面数量为 0 ~ n-1 ,选择反面硬币抛,抛出结果正面数量比原本 +1 或 不变

  ②.正面数量为 n,只能够选择正面硬币抛,抛出结果正面数量比原本 -1 或 不变

 

设dp数组, dp[i][j] 表示: 第 i 次抛硬币后, j 个硬币正面朝上的概率

一、当 j < n 时,对应上文情况①,选择了一个反面的硬币,正面数量会比原本 +1 或 不变那么这个概率dp[i][j]将一分为二,传递到dp[i+1][j]dp[i+1][j+1],即:

for(int j=0;j

 

二、当 j = n 时,对应上文情况②,选择了一个正面的硬币,正面数量会比原本 -1 或 不变那么这个概率dp[i][j]将一分为二,传递到dp[i+1][j]dp[i+1][j-1],即:

dp[i+1][n]+=dp[i][n]/2;
dp[i+1][n-1]+=dp[i][n]/2;

如此递推即可求出n个硬币抛k次的所有正面朝上次数的概率,最后求数学期望即可

例:n=2 时的dp转移表格(抛币次数为2,正面数量为2时,即为上文情况②):

Gym - 101606F 抛硬币(概率dp)_第2张图片

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
double dp[410][410], ans;
int main(){
	int n, k;
	while (~scanf("%d %d", &n, &k)){
		for (int i = 0; i <= 400; i++)
			for (int j = 0; j <= 400; j++)
				dp[i][j] = 0;
		dp[0][0] = 1;
		for (int i = 0; i < k; i++){
			for (int j = 0; j < n; j++){
				dp[i + 1][j] += dp[i][j] * 0.5;
				dp[i + 1][j + 1] += dp[i][j] * 0.5;
			}
			dp[i + 1][n] += dp[i][n] * 0.5;
			dp[i + 1][n - 1] += dp[i][n] * 0.5;
		}
		ans = 0;
		for (int i = 1; i <= n; i++)
			ans += i*dp[k][i];
		printf("%.8lf\n", ans);
	}
	return 0;
}

 

你可能感兴趣的:(dp)