开拓计划3 - DP入门

开拓计划3 - DP入门

DP

DP的概念

  • Q:什么是DP?
  • A:动态规划(DP),是指在实现问题时有多种方法,而每次都取最优的方案,解决问题。
  • Q: DP和贪心有什么区别?
  • A: DP是将问题分成很多类方案再整合出最优的,贪心是将问题分成很多步每一步最优推出全局最优。

DP五部曲

  1. 设定状态:根据题目需要,设定 \(dp_{i,j,k,......}\) 表示的含义。一般问什么设什么。
  2. 递推公式:将当前状态分成几类实现方案,一类就是一种转移。
  3. 初始化:确定 \(dp\) 数组应当如何设定初始值。
  4. 遍历顺序:这点容易被忽视,却至关重要,特别是在背包问题中。
  5. 输出答案:答案有时需要单独在数组里面找,而不是直接输出数组的某一个位置。

NKOJ 1796 【USACO1.5.1】Number Triangles 数字金字塔

思路:典型的二维DP

实现方法

  1. \(dp_{i,j}\) 表示走到第 \((i,j)\) 个点的时候能取得的最大价值。
  2. 有两种方案,从正上方和左上方,递推公式:\(dp_{i,j}=\max(dp_{i-1,j},dp_{i-1,j-1})+arr_{i,j}\)
  3. 取最大值且没有负数,不用单独赋初始值。
  4. 从头到尾遍历。
  5. 答案是最后一排的所有数中的最大值。

NKOJ 1050 马拦过河卒(NOIP)

思路:同NKOJ 1796

区别

  • 更改枚举顺序(从八个方向)和DP数组含义

NKOJ 1001 最小乘车费用

思路:典型的线性DP

实现方法

  1. 定义 \(dp_i\) 表示乘坐 \(i\) 站时的最小乘车费用。
  2. 有多种方案,直接乘坐或换乘。
  3. 初始值为无穷大。
  4. 从头到尾遍历 \(i\),从 \(\min(i-10,0)\) 枚举到 \(i\)
  5. 答案是\(dp_n\)

NKOJ 1043 最大连续子序列

思路:贪心 / DP

贪心版

  • 遇到数,如果加上第 \(i\) 位整体变成负的了,那对后续没有好处,不如放弃这一整段从第 \(i+1\) 位重新开始。

DP版

  1. \(dp_i\) 表示当第 \(i\) 个数必须取得时候,能得到的最大字段和。
  2. 有两种方案,自己新开一段或跟着上一段的末尾,递推公式:\(dp_i=\max(dp_{i-1}+arr_i,arr_i)\)
  3. 由于有可能有负数,所以 \(dp\) 数组应当初始化为负无穷。
  4. 从头到尾遍历。
  5. 答案是整个数组中的最大值。

NKOJ 1049 【NOI1997 Day2 T1】最佳游览

思路:同NKOJ 1043

区别

  • 输入的是二维数组,要先求出每一列的最大值,将最大值存下来,再在最大值数组中寻找最大字段和。

LIS

LIS的定义

  • Q:什么是LIS?
  • A:LIS(最长上升子序列),求一个序列中所有子序列里面,元素满足单调性的子序列,最长是多少。

LIS的求法

  1. \(dp_i\) 表示以 \(arr_i\) 结尾的最长上升子序列的长度。
  2. 有两种方案。
    • 自己单飞。
    • 跟前面的连。

得到

\[dp_i =\max(1+dp_j,dp_i)\text{ 当}arr_i>arr_j\text{且} 1\le j \le i \]

时间复杂度 \(O_{n^2}\) 有点高。

LIS求法的优化

  1. 更改 \(dp_i\) 的含义。改为表示长度为 \(i\) 的最长上升子序列的尾元素。
  2. 有两种情况。
    • 能接上一个,作出新贡献。
    • 接不了找能接的,接上。

得到

\[\begin{cases} dp_{++cnt}=arr_i & arr_i>dp_{cnt} \\ dp_{\text{找到的能接的}}=arr_i & \text{other} \end{cases} \]

找的过程可以用二分,时间复杂度 \(O_{n\log n}\)


NKOJ 2017 渡轮问题(变态版)

模板题。

NKOJ 2508 渡轮问题(弱数据版)

模板题。

NKOJ 1004 拦截导弹

模板题。

NKOJ 1042 合唱队形(NOIP)

前后各遍历一次,取和。

LCS

LCS的定义

  • Q:什么是LCS?
  • A:LCS(最长公共子序列),求两个序列中所有子序列里面,元素完全相同的子序列,最长是多少。

LCS的求法

  1. \(dp_{i,j}\) 表示以 \(arr_i\)\(brr_j\) 结尾时最长公共子序列的长度。
  2. 有两种情况。
    • \(arr_i=brr_j\) 时,直接加入LCS。
    • 不然就取两个序列上一个的最大长度。

得到

\[dp_{i,j}=\begin{cases} dp_{i-1,j-1}+1 & arr_i=brr_j \\ \max(dp_{i-1,j},dp_{i,j-1}) & \text{other} \end{cases} \]


NKOJ 1051 最长公共子序列

模板题。

NKOJ 3636 三个序列的最长公共子序列

模板提,把两个改为三个。

NKOJ 1052 最长公共子串

模板题,子串要求连续,遇到不相等的直接等于零,可以压维。


NKOJ 1035 咒语

思路:LIS与LCS综合

实现方法

  1. \(dp_{i,j}\) 为当 \(arr_i\) 必取,\(brr_j\) 不一定取的情况下的最长连续上升子序列的长度。
  2. 共两种情况,\(arr_i = brr_j\) 时前面最长的再 \(+1\) ,或 \(arr_i < brr_j\) 此时应当更新前缀最大值。
  3. 无初始值。
  4. 先遍历 \(j\) 再遍历 \(i\)
  5. \(dp\) 数组的最大值。
posted @ 2024-12-14 09:58  hsr_ray  阅读(104)  评论(0)    收藏  举报