Gym 101606 F-Flipping Coins(概率dp)
参考博客:http://www.cnblogs.com/kang000/p/8571071.html (这篇博客写的真的走心,ORZ)
题意
有n个硬币排成一排,开始的时候所有的硬币都是正面朝下,你必须要扔K次硬币,每次选择一个硬币,如果你采取最优策略,K次以后朝上的硬币数的最大期望是多少?
分析
一脸懵逼两脸懵逼三脸懵逼···
--------------------------------------------------------------------------
随机变量X是指朝上的硬币数,当有N枚硬币的时候,X=0,1,2,3....N
E(X)=1*p(1)+2*p(2)+....+n*p(n)。
要想求最大期望,我们在扔硬币的时候要遵循一个策略:尽量扔正面朝下的硬币
如果当前有0到n-1枚硬币正面朝上,我们可以选择正面朝下的硬币来扔,扔完以后朝上硬币数不变或者+1
如果当前有n枚硬币正面朝上,我们只能选择正面朝上的硬币来扔,扔完以后朝上的硬币数不变或者-1
-----------------------------------------------------------------------------------------------
令dp[i][j]为扔i次以后j枚硬币朝上的概率
根据上面总结的规律,我们可以的到状态转移方程
当j<n的时候
dp[i+1][j]+=dp[i][j]*0.5
dp[i+1][j+1]+=dp[i][j]*0.5
当j=n的时候
dp[i+1][j+1]+=dp[i][j]*0.5
dp[i+1][j-1]+=dp[i][j]*0.5
这样递推出概率来以后遍历一遍j求期望就好了~
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 6 using namespace std; 7 const int maxn=500; 8 double dp[maxn][maxn]; 9 int n,k; 10 int main(){ 11 scanf("%d%d",&n,&k); 12 memset(dp,0,sizeof(dp)); 13 dp[0][0]=1; 14 15 for(int i=0;i<k;i++){ 16 for(int j=0;j<=n;j++){ 17 if(j<n){ 18 dp[i+1][j]+=0.5*dp[i][j]; 19 dp[i+1][j+1]+=0.5*dp[i][j]; 20 } 21 if(j==n){ 22 dp[i+1][j]+=0.5*dp[i][j]; 23 dp[i+1][j-1]+=0.5*dp[i][j]; 24 } 25 } 26 } 27 /*for(int i=0;i<=k;i++){ 28 for(int j=0;j<=n;j++){ 29 printf("%d %d %f\n",i,j,dp[i][j]); 30 } 31 }*/ 32 double ans=0; 33 for(int i=1;i<=n;i++){ 34 ans+=dp[k][i]*i; 35 } 36 printf("%.6f",ans); 37 38 return 0; 39 }