HDU 6558 The Moon

题意:
进行一局游戏,你有 p 的概率获胜。有一个概率 q 初始为 2% ,如果你获胜,你将有 q 的概率获得奖励;如果你没得到奖励, q 会变化, q = m i n ( 100 % , q + 2 % ) q=min(100\%,q+2\%) ;如果你输了, q 也会变化, q = m i n ( 100 % , q + 1.5 % ) q=min(100\%,q+1.5\%)
问获得奖励的期望局数为多少。

分析:
很明显的期望 dp 。对于普通的期望 dp ,一般是把结局的概率作为1,从开始进行记忆化递归。但是对于本题。开始时没有得到奖励,就是0,得到奖励就是1,只有 0->1 ,显然不行。
既然是dp,那就要有多条转移路径的状态,将状态作为dp数组的下标。发现本题中 q 是有多条转化的路径的,我们不妨将 q 作为状态。但是作为数组下标一定要是整数,那就 10 *10 ,即100%对应 d p [ 1000 ] dp[1000] ,25.5%对应 d p [ 255 ] dp[255]
d p [ i ] dp[i] 表示当 q = i / 1000 q=i/1000 时,得到奖励的期望。

期望=概率*局数

d p [ i ] = ( 1 p ) ( d p [ m i n ( i + 15 , 1000 ) ] + 1 ) dp[i]=(1-p)*(dp[min(i+15,1000)]+1) //这一局没赢,以后获得了奖励;

+ p q 1 +p*q*1 //这一局赢了,且获得了奖励;

+ p ( 1 q ) ( d p [ m i n ( i + 20 , 1000 ) ] + 1 ) +p*(1-q)*(dp[min(i+20,1000)]+1) //这一局赢了,但没获得奖励,以后获得了奖励,别忘了*(1-q),代表没获得奖励

注意转移的时候要加1,即当前没赢的这一局。本局直接获得奖励的话,所需局数是1;否则就是下一个状态的局数+1.

我们把上下两项的“1”提出来,与p*q组合

( 1 p ) + p q + p ( 1 q ) = 1 (1-p)+p*q+p*(1-q)=1

综上所述, d p [ i ] = ( 1 p ) d p [ m i n ( i + 15 , 1000 ) ] + 1 + p ( 1 q ) d p [ m i n ( i + 20 , 1000 ) ] dp[i]=(1-p)*dp[min(i+15,1000)]+1+p*(1-q)*dp[min(i+20,1000)]

那么开始时状态就是 d p [ 20 ] dp[20] , 结束时状态就是 d p [ 1000 ] dp[1000]

d p [ 1000 ] 1 , d p [ 1000 ] = 1 p dp[1000]\neq1,dp[1000]=\frac{1}{p} 即使 q = 100 % q=100\% ,但是可能这局输了,根本就没机会的奖励

因为直接写的等于1,检查了好久

证明其实就是很简单,如果这一把输了,下一把的q仍为100%。

d p [ 1000 ] = E dp[1000]= E

E=(1-p)*E+1+p*(1-1)*E

化简可得 E = 1 p E=\frac{1}{p}

至此,答案显然易见。

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int N=1e3+5;
const double eps=1e-6;
typedef long double ld; 
ld dp[N];
ld p;
void dfs(int rate)
{
    ld q=(double)rate/1000.0;
    int nxt1=min(rate+15,1000),nxt2=min(rate+20,1000);
    if(nxt1<1000&&fabs(dp[nxt1])<eps) dfs(nxt1);
    if(nxt2<1000&&fabs(dp[nxt2])<eps) dfs(nxt2);
    dp[rate]=(1-p)*dp[nxt1]+1+p*(1-q)*dp[nxt2];
}
int main()
{
    int t;
    cin>>t;
    for(int it=1;it<=t;it++)
    {
        cin>>p;
        memset(dp,0,sizeof(dp));
        p/=100;
        dp[1000]=1.00/p;
        dfs(20);
        cout<<"Case "<<it<<": "<<fixed<<setprecision(10)<<dp[20]<<endl;
    }
}

猜你喜欢

转载自blog.csdn.net/Luowaterbi/article/details/106323284