基础动态规划总结

 DP模型

DP 的分类

DP问题可以分为线性和非线性的。

  1. 线性DP,线性DP有两种方法,即顺推(自下向上,常写成循环嵌套的形式)与倒推(自上向下,常写成记忆化搜索)。

  2. 非线性DP,例如树形DP,建立在树上,也有两个方向:①根→叶,根传递有用的信息给子节点,最后根得出最优解;②叶→根,根的子节点传递有用的信息给根,最后根得到最优解。

NOIP普及组常考的DP类型有如下几种:

  • 线性DP: 线性动态规划,即具有线性阶段划分的动态规划。问题的模型是线性的,数据结构表现为线性表(数组)的形式。经典的问题包括:递推、最长公共子序列、最长递增子序列以及01背包问题。
  • 背包DP: 背包动态规划是线性动态规划中特殊的一类,NOIP中考到的次数很多。一般用状态 f[i][j]f[i][j] 来表示 1\sim i1∼i 件物品装进容量是 jj 的背包时的 最大价值,背包型DP可以利用滚动数组优化成一维,但时间复杂度仍为 O(n^2)O(n2)。
  • 区间DP: 区间动态规划一般以区间作为动态规划的阶段。一般这类问题有个明显的特点:就是给出的问题是按区间的性质进行,要么合并,要么分解为区间操作。一般用状态 dp[l][r]dp[l][r] 来表示从左端点 ll 到右端点 rr 这个区间上问题的 最优解
  • 矩阵DP: 矩阵类型,线性DP中特殊的一类,就是给出的数据模型就是一个二维矩阵,通常,在问题中给出了明确的决策,即在矩阵中进行操作。

DP 的特点

dp特点:dp把原问题视作若干个 重叠 的子问题的逐层递进,每个子问题的求解过程都会构成一个“阶段”,在完成一个阶段后,才会执行下一个阶段。

dp要满足无后效性:已经求解的子问题 不受后续阶段的影响

DP 的解题要素

  1. 设计状态:设计dp数组的含义,它要满足无后效性。
  2. 设计状态转移方程:子问题之间是如何逐层递进的。递推型 DP 是通过一个转移方程实现的,记忆化搜索是通过递归求解子问题实现的。

背包问题

给定 nn 个重量为 w_1,w_2,...,w_nw1​,w2​,...,wn​ ,价值为 v_1,v_2,...,v_nv1​,v2​,...,vn​ 的物品,要放进一个只能装最大重量为 CC 的背包,问,如何选择物品放入,才能使这个背包内的物品的总价值最大?求这个最大价值。

值得注意的是: 01背包问题是所有背包类问题的最基础的模型,其他类型的背包问题都可以通过将 01 背包的模型进行一些转化后得到。因此,01 背包一定要牢固掌握。

01背包

限制条件:每种物品只有一件,可以选择装(一件)或不装(装零件)。

定义状态

  • 定义 f[i][j]f[i][j] 来表示将前 ii 件物品放入容量为 jj 的背包中时,所能获得的最大价值。容易得到,目标状态(我们最终要求的答案)就是 f[n][C]f[n][C]。

状态转移方程

  • 考虑第 ii 件物品:
    • 不放:f[i][j] = f[i-1][j]f[i][j]=f[i−1][j]
    • 放:f[i][j] = f[i-1][j-w_i] + v_i, j-w_i>=0f[i][j]=f[i−1][j−wi​]+vi​,j−wi​>=0
    • 最终方程:f[i][j] = max(f[i-1][j], f[i-1][j-w_i] + v_i)f[i][j]=max(f[i−1][j],f[i−1][j−wi​]+vi​)
    • 可以优化掉状态的第一维,来降低空间复杂度
const int N = 1e4+5;
int n, m, w[N], v[N], dp[N];   // dp[i]: 装满体积是 i 的背包,能装的最大价值

int main(){
    cin >> m >> n;   // m: 背包体积   n:物品数量
    for(int i = 1; i <= n; i++)
        cin >> w[i] >> v[i];    // 物品重量 和 价值
    
    for(int i = 1; i <= n; i++)   // 枚举物品
        for(int j = m; j >= w[i]; j--)     // 倒序枚举体积
            dp[j] = max(dp[j-w[i]]+v[i], dp[j]);
    
    cout << dp[m];
    return 0;
}

Copy<

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值