动态规划基础

引入

动态规划简介

  • 动态规划 dp=Dynamic Programming
  • 线性 dp:状态定义与题设线性相关
  • 将原问题分解成若干子问题
  • 设计状态:状态是当前问题所在的局面
  • 满足性质:无后效性,最优子结构
  • 转移:状态之间的关系,用转移方程描述
  • 动态规划(递推)记忆化搜索(递归) 时间复杂度相同
    • 记忆化搜索可以规避转移顺序,且方便处理边界情况
    • 记忆化搜索效率较低,且难以优化、调试

例子:最长上升子序列

  • 状态:以第 x 个元素结尾的最长上升子序列(LIS)的长度,用 fx 表示
  • 转移:最长上升子序列一定是接在某个上升子序列尾部形成的
  • 刻画整体的转移路径:
    • 把每一个状态视作一个节点,把状态转移视作一条有向边,串联起来构成有向无环图DAG
    • 所以根据拓扑序对图进行遍历来求解问题(拓扑排序)
    • 动态规划遍历顺序称为阶段

动态规划三要素

  • 状态(描述问题局面)
  • 转移(状态之间的数学关系)
  • 阶段(计算状态的顺序)

B3635 硬币问题

  • 题意简述:用 1, 5, 11 元的硬币凑出 n 元,最少需要多少硬币?
  • 状态:dpn 表示凑出 n 元所需要的最少硬币数量
  • 转移:dpi=min(dp[i1],dp[i5],dp[i11])+1
  • 解释:凑出 n 元有三种局面
    • 凑出 n1 元,拿出一个 1 元硬币
    • 凑出 n5 元,拿出一个 5 元硬币
    • 凑出 n11 元,拿出一个 11 元硬币
    • 取三个当中的最小值

一维线性 dp

例题:P1091

  • 使用 dp 求出 LIS 和 LDS,枚举中间最高的那个人

优化最长上升子序列

  • 第一种枚举时间复杂度 O(n2),但存在大量重复枚举
  • 记录以前选的所有数的下标,对于元素 x
    • 如果 x 小于最大值,那么替换掉第一个大于它的数
    • 如果 x 大于最大值,那么插入到最后
  • 优化后时间复杂度 O(n log n)

二维线性 dp

例题:P1216

  • 状态:设 f[i][j] 表示到了位置 (i,j) 时可以得到的最大数字和
  • 转移:f[i][j]=max(f[i1][j1],f[i1][j])+a[i][j]

例子:最长公共子序列

  • 给定两个序列 A,B,求最长公共子序列(LCS)的长度

优化前

  • 状态:f[i,j] 表示第一个排列前 i 个元素和第二个排列前 j 个元素,最长公共子序列的长度
  • 转移:f[i,j]=f[i1][j1]+1,Ai=Bj

f[i,j]=max(f[i1][j],f[i][j1]),AiBj

f[i][j]={f[i1][j1]+1A[i]=B[j]max(f[i1][j],f[i][j1])A[i]B[j]

优化后

  • 重新标号:把 A 用字母标成单调递增数列,再用这样的标号标记 B,求 B 的最长上升序列

例题:P1004

  • f[step][a][b][x][y] 表示走了 step 步,甲走到 (a,b),乙走到 (x,y)
  • 把 step 一维省略:变为四维 dp
  • f[step][a][b][x][y]=+
    • f[step][a1][b][x1][y]
    • f[step][a1][b][x][y1]
    • f[step][a][b1][x1][y]
    • f[step][a][b1][x][y1]

背包 dp

01 背包(一个物品只能选择一次)

  • w 表示重量,v 表示价值,N 表示物品个数,W 表示背包容量,f 表示 dp 数组
  • 注意:第二层循环必须从大到小枚举
for (int i = 1; i <= N; i ++) {
    for (int j = W; j >= w[i]; j --)
        f[j] = max(f[j], f[j - w[i]] + v[i]);
}

完全背包(每个物品可以无限次选择)

for (int i = 1; i <= N; i ++) {
    for (int j = w[i]; j <= W; j ++)
        f[j] = max(f[j], f[j - w[i]] + v[i]);
}

多重背包(每个物品可以选择 ki 次)

  • 第一种:转换成 01 背包
    • 时间复杂度 O(nWki)
  • 第二种(二进制优化):把每个 k 拆成二进制表示,即1+2+4+...+2n,变成了 log ki,再进行 01 背包
    • 时间复杂度 O(nWlog ki)

混合背包例题:P1833

  • 由于总时间有限,把完全背包的无限次转化为 1000
  • 01 背包就是多重背包中的 k=1

分组背包例题:P1757

  • 物品被划分成 k 组,每一组内只能选择最多 1 个物品
  • 组内先枚举物品重量,再内聚物品编号
  • 共三维:组、重量、编号

依赖背包例题:P1064

  • 每一种主件的四种情况
    • 只购买主件
    • 购买主件,附件 A
    • 购买主件,附件 B
    • 购买主件,附件 AB

区间 dp

区间 dp 介绍

  • 在区间上做动态规划,求在区间上的最优解
  • 区间 dp 的状态通常包括区间信息 (l,r)
  • 子区间信息满足区间加法
  • 分治思想:大区间信息由小区间获得

区间 dp 例题:P1775

对环形问题的处理

  • 使用破环成链的思想
  • 将数组倍长,令 a[i+n]=a[i]

环上 dp 例题:P1063

  • f[l][r] 表示将 [l,r] 范围内全部能量珠合并释放的最大能量,可得 f[l][r]=max(f[l][k]+f[k+1][r]+a[l]×b[i]×b[r])
posted @   SuperUser777  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示