【GYM 101606F】Flipping Coins (概率dp)

版权声明:若转载请附上原博客链接,谢谢! https://blog.csdn.net/Link_Ray/article/details/89292941

https://codeforces.com/gym/101606/problem/F

题意

初始有n枚硬币正面朝下,一共要抛硬币m次,每次都是以最优的策略抛,问最后正面朝上的硬币的期望是多少。
1<=n,m<=400

题解

最优的策略即不到万不得已不会选已经是正面的硬币抛,一开始想的是用一个公式解出这题,其实这是很不现实的,因为总会以最优的策略抛,根本就没法用公式来代替,况且数据范围是400,组合数也算不下。

因为太少接触概率dp,所以根本看不出来。

dp[i][j]:j次有i枚硬币朝上的概率。

  1. i<n
    dp[i+1][j+1] = dp[i][j]*0.5
    dp[i][j+1] = dp[i][j]*0.5
  2. i == n
    dp[i][j+1] = dp[i][j]*0.5
    dp[i-1][j+1] = dp[i][j]*0.5

因为一旦 i==n那么策略就不一样了,不能用同一个转移方程。 这里最外层应该枚举j,因为j是有序的,总是会用到j-1,为什么不能枚举i呢,因为i-1会在i的时候更新,有后效性。

代码

#include <bits/stdc++.h>
using namespace std;
#define FOR0(a,b) for(int i = a; i < b; ++i)
#define FORE(a,b) for(int i = a; i <= b; ++i)
typedef long long ll;
typedef pair<int,int> pii;

const int maxn = 405;
int n,k;
double dp[maxn][maxn];
int main() {
scanf("%d%d", &n, &k);
dp[0][0] = 1;
for(int j = 0; j <= k; ++j) {
for(int i = 0; i <= n; ++i) {
if(i == n) {
dp[i-1][j+1] += dp[i][j]*0.5;
dp[i][j+1] += dp[i][j]*0.5;
} else {
dp[i+1][j+1] += dp[i][j]*0.5;
dp[i][j+1] += dp[i][j]*0.5;
//cout << i <<" " << j << " " << dp[i][j] <<" " << dp[i+1][j+1]<< endl;
}
}

}

double ans = 0;
for(int i = 1; i <= n; ++i)
    ans += i*dp[i][k];
printf("%.8lf\n", ans);
return 0;

}

猜你喜欢

转载自blog.csdn.net/Link_Ray/article/details/89292941