首页 > 代码库 > 读书笔记 -- 动态规划 + 离散化

读书笔记 -- 动态规划 + 离散化

技术分享

半夜睡不着,起来看看书,就看到了这题,费了大半个小时才看明白,然后不困了Orz。

书上都有代码,但是为什么我再敲一遍。如果没明白我是不会抄一遍的,那样没有意义。

看到能给我启发的题目,我觉得还是记录下来比较好,毕竟0-1背包,自己还没有写过小数版的Orz。

 

本来也不怎么会说,还不如课本说的清楚。直接截图吧。

技术分享

 

状态转移方程:

从后往前推:dp[i][j] 表示第还剩i轮次,当前的金币数为j。

设第i次的选择是拿出k当作赌注,那么输了概率是1-p,最后的钱是j-k,如果赢了,最后的钱是j+k,

那么作为金钱数j的当前轮次所能赢的最终钱的概率的最优选择是最合适的k,让他的概率最高。

dp[i][j] =max{ dp[i-1][j+k]*p + dp[i-1][j-k]*(1-p)}

使用滚动数组来节省内存,不过不用也应该是可以的,M最大是16

#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
typedef long long LL;
const int MAXM = 16;

double dp[2][1 << MAXM | 1];
int  M, X;
double P;
void solve()
{
    memset(dp, 0, sizeof(dp));
    int n = 1 << M;
    dp[0][n] = 1.0;

    for(int r = 1; r <= M; r++)
    {
        for(int i = 0; i <= n; i++)
        {
            double t = 0.0;
            int duzhu = min(i, n - i);
            for(int j = 0; j <= duzhu; j++)
            {
                t = max(t, P * dp[!(r & 1)][i + j] + (1 - P) * dp[!(r & 1)][i - j]);
            }
            dp[r & 1][i] = t;
        }
    }
    int x = (LL)X * n / 1000000;
    printf("%.6f\n", dp[M & 1][x]);
}

int main()
{
    scanf("%lf%d%d", &P, &X, &M);
    solve();
    return 0;
}

读书笔记 -- 动态规划 + 离散化