动态规划(DP)

1. 线性DP

线性DP是指状态转移方程沿着线性阶段展开,通常是一维或二维的状态,按顺序递推。

例题1.1:最长上升子序列(LIS)

问题描述:给定一个长度为 \(N\) 的数列,求数值严格单调递增的子序列的长度最长是多少。

思路提示:设 \(dp[i]\) 表示以第 \(i\) 个元素结尾的最长上升子序列的长度,则状态转移方程为:\(dp[i] = \max(dp[j]) + 1\),其中 \(j < i\)\(a[j] < a[i]\)

例题1.2:最长公共子序列(LCS)

问题描述:给定两个字符串 \(A\)\(B\),求它们的最长公共子序列的长度。

思路提示:设 \(dp[i][j]\) 表示 \(A\) 的前 \(i\) 个字符和 \(B\) 的前 \(j\) 个字符的最长公共子序列长度。状态转移方程:如果 \(A[i] = B[j]\),则 \(dp[i][j] = dp[i-1][j-1] + 1\);否则,\(dp[i][j] = \max(dp[i-1][j], dp[i][j-1])\)

2. 区间DP

区间DP的状态通常表示为区间,转移时由小区间合并成大区间。

例题2.1:合并石子

问题描述:有 \(N\) 堆石子排成一排,每堆石子有一定的数量。现要将 \(N\) 堆石子合并成为一堆。每次只能合并相邻的两堆,合并的代价为这两堆石子的数量之和。找出一种合理的方法,使总的代价最小。

思路提示:设 \(dp[i][j]\) 表示合并区间 \([i, j]\) 的石子所需的最小代价。状态转移方程:\(dp[i][j] = \min(dp[i][k] + dp[k+1][j] + sum[i][j])\),其中 \(k\)\([i, j-1]\) 之间,\(sum[i][j]\) 表示区间 \([i, j]\) 的石子总数。

例题2.2:多边形

问题描述:给定一个多边形,每个顶点有一个整数,每条边是 \(+\)\(*\)。首先删除一条边,然后每次可以将两个顶点合并为一个顶点,即用一条边连接的两个顶点合并,新的顶点的值为原来两个顶点按照边的符号运算的结果。求通过合并最终得到一个顶点的最大值。

思路提示:这是一个环形区间DP问题。首先将环拆成链,复制一遍。设 \(dp[i][j]\) 表示区间 \([i, j]\) 合并的最大值,同时需要维护一个最小值(因为可能有负数相乘得到正数)。状态转移时根据中间的运算符和区间分割点进行转移。

3. 树形DP

树形DP是在树结构上进行的动态规划,通常从根节点开始递归处理子树。

例题3.1:树的最长路径(直径)

问题描述:给定一棵树,树中包含 \(n\) 个结点(编号 \(1\)~\(n\))和 \(n-1\) 条无向边,每条边都有一个权值。求树中一条路径,使得路径上边的权值之和最大。

思路提示:对于每个节点,记录从该节点向下走的最长路径和次长路径,那么经过该节点的最长路径就是最长路径加上次长路径。在树中DFS,更新答案。

例题3.2:没有上司的舞会

问题描述:某大学有 \(N\) 个职员,编号为 \(1\)~\(N\)。他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。每个职员有一个快乐指数。现在要召开一场宴会,没有职员愿意和直接上司一起参加。求邀请哪些职员可以使快乐指数最大。

思路提示:设 \(dp[u][0]\) 表示以 \(u\) 为根的子树,不选 \(u\) 节点时的最大快乐指数;\(dp[u][1]\) 表示选 \(u\) 节点时的最大快乐指数。状态转移:\(dp[u][0] = \sum \max(dp[v][0], dp[v][1])\)\(dp[u][1] = \sum dp[v][0] + happy[u]\),其中 \(v\)\(u\) 的子节点。

4. 状态压缩DP

状态压缩DP通常用于处理集合状态,用一个整数的二进制位表示一个集合。

例题4.1:旅行商问题(TSP)

问题描述:给定一个 \(n\) 个点的带权无向图,求从点 \(0\) 出发,经过所有点恰好一次并回到起点的最短路径。

思路提示:设 \(dp[S][i]\) 表示已经访问过的城市集合为 \(S\),当前所在城市为 \(i\) 的最小花费。状态转移:\(dp[S][i] = \min(dp[S-\{i\}][j] + dist[j][i])\),其中 \(j\) 属于 \(S\)\(j \neq i\)\(S\) 用二进制数表示。

例题4.2:蒙德里安的梦想

问题描述:给定一个 \(n\)\(m\) 列的棋盘,用 \(1 \times 2\) 的骨牌铺满,问有多少种铺法。

思路提示:按行进行DP,状态为当前行的覆盖情况(二进制表示)。设 \(dp[i][j]\) 表示前 \(i-1\) 行已经铺满,第 \(i\) 行的状态为 \(j\)\(j\) 的每一位表示该列是否被上一行延伸的骨牌覆盖)的方案数。转移时枚举下一行的状态,要求当前行和下一行不能冲突(即当前行空位必须由竖着的骨牌覆盖,下一行对应位置被覆盖,且下一行不能有连续两个空位,因为横着的骨牌需要两个连续空位)。

5. 数位DP

数位DP用于处理与数字的每一位相关的问题,通常计算在某个区间内满足条件的数字个数。

例题5.1:数字计数

问题描述:给定两个正整数 \(a\)\(b\),求在 \([a, b]\) 中的所有整数中,每个数字(\(0\)~\(9\))各出现了多少次。

思路提示:分别计算 \(0\)\(a-1\)\(0\)\(b\) 中每个数字出现的次数,然后相减。使用数位DP,设状态为当前处理到第几位、前面是否达到上限、以及前导零等。

例题5.2:不含连续数字的非负整数

问题描述:给定一个正整数 \(n\),求在 \([0, n]\) 中,其二进制表示不包含连续 \(1\) 的数的个数。

思路提示:将 \(n\) 转换为二进制,从高位到低位DP。设 \(dp[pos][last]\) 表示处理到第 \(pos\) 位,上一位是 \(last\)\(0\)\(1\))时的方案数。注意限制不能超过 \(n\)

6. 概率/期望DP

概率/期望DP用于处理概率和期望问题,通常状态转移涉及到概率。

例题6.1:收集邮票

问题描述:有 \(n\) 种邮票,每次等概率随机得到一种邮票,得到第 \(i\) 种邮票的概率为 \(1/n\)。求收集到所有 \(n\) 种邮票的期望次数。

思路提示:设 \(dp[i]\) 表示已经收集到 \(i\) 种邮票,要收集到 \(n\) 种邮票的期望次数。状态转移:\(dp[i] = i/n \times (dp[i] + 1) + (n-i)/n \times (dp[i+1] + 1)\),解方程得到 \(dp[i] = dp[i+1] + n/(n-i)\)

例题6.2:迷宫

问题描述:给定一个迷宫,某些位置有陷阱,每次移动会等概率向周围可走的方向移动,求从起点到终点的期望步数。

思路提示:设 \(dp[i]\) 表示从位置 \(i\) 到终点的期望步数。对于每个位置,列出方程:\(dp[i] = 1 + \sum(dp[j] \times p_j)\),其中 \(j\)\(i\) 可以到达的位置,\(p_j\) 是移动到 \(j\) 的概率。然后使用高斯消元求解。

7. 背包DP

背包DP是DP中的经典问题,主要分为01背包、完全背包、多重背包等。

例题7.1:01背包

问题描述:有 \(N\) 件物品和一个容量为 \(V\) 的背包。第 \(i\) 件物品的体积是 \(v[i]\),价值是 \(w[i]\)。求解将哪些物品装入背包可使价值总和最大。

思路提示:设 \(dp[j]\) 表示容量为 \(j\) 的背包能装的最大价值。状态转移:\(dp[j] = \max(dp[j], dp[j - v[i]] + w[i])\),注意倒序枚举 \(j\)

例题7.2:完全背包

问题描述:有 \(N\) 种物品和一个容量为 \(V\) 的背包,每种物品都有无限件可用。第 \(i\) 种物品的体积是 \(v[i]\),价值是 \(w[i]\)。求解将哪些物品装入背包可使价值总和最大。

思路提示:设 \(dp[j]\) 表示容量为 \(j\) 的背包能装的最大价值。状态转移:\(dp[j] = \max(dp[j], dp[j - v[i]] + w[i])\),注意正序枚举 \(j\)

8. 计数DP

计数DP用于统计满足条件的方案数。

例题8.1:整数划分

问题描述:将正整数 \(n\) 划分为若干个正整数的和,求划分的方案数(不考虑顺序)。

思路提示:可以看作是完全背包问题:有 \(1\)\(n\)\(n\) 种物品,每种物品无限个,背包容量为 \(n\),求恰好装满背包的方案数。\(dp[j]\) 表示和为 \(j\) 的方案数,转移:\(dp[j] = dp[j] + dp[j-i]\)

例题8.2:卡特兰数

问题描述:求 \(n\) 个节点构成的二叉搜索树的数量。

思路提示:设 \(dp[n]\) 表示 \(n\) 个节点构成的二叉搜索树的数量。考虑根节点,左子树有 \(i\) 个节点,右子树有 \(n-1-i\) 个节点,则 \(dp[n] = \sum(dp[i] \times dp[n-1-i])\),其中 \(i\)\(0\)\(n-1\)

9. 动态规划优化

动态规划优化包括单调队列优化、斜率优化、四边形不等式优化等。

例题9.1:滑动窗口最大值优化DP

问题描述:给定一个长度为 \(n\) 的数组 \(a\),和一个长度为 \(k\) 的滑动窗口,求每次滑动窗口中的最大值。

思路提示:使用单调队列维护窗口中的最大值,队列中存储下标,保证队列中的元素对应的值单调递减。

例题9.2:斜率优化DP

问题描述:有 \(n\) 个任务排成一个序列,每个任务有一个完成时间 \(t\) 和费用系数 \(c\)。将任务分成若干批,每批任务连续,开始时间相同。每个任务的完成费用为完成时间乘以费用系数。求最小总费用。

思路提示:设 \(dp[i]\) 表示前 \(i\) 个任务的最小费用。状态转移:\(dp[i] = \min(dp[j] + (sumT[i] - sumT[j] + S) \times sumC[i])\),其中 \(j < i\)。将转移方程变形为 \(y = kx + b\) 的形式,然后维护一个下凸壳,用单调队列优化。

posted @ 2026-01-11 17:25  Chestify  阅读(3)  评论(0)    收藏  举报