动态规划解决问题的基本方式是( )。
考点:DP 的定义(A1)。
(A1)考点:DP 的定义——分解为重叠子问题,用状态记录答案按序推进。
解析:本题考查 DP 的定义。DP 的骨架:把原问题拆成一族小问题,每个小问题的答案存进 dp 数组的一格;算大问题时直接查表,不重算。与「一次扫描出答案」的贪心不同,DP 显式管理所有子问题。
排除法:A 选排序再扫描的人描述的是排序算法;C 选每次局部最优不反悔的人描述的是贪心;B 选全部列举逐个检查的人描述的是暴力枚举,DP 恰恰是为了避免重复枚举而生。
DP 中「状态」与「转移」分别指( )。
考点:状态与转移(A2)。
(A2)考点:状态与转移——状态是子问题的抽象(dp 数组一格),转移是子问题间的推导关系。
解析:本题考查状态与转移。状态回答「这格装的是哪个子问题的答案」,转移回答「这格怎么由更小的格算出来」。写 DP 前能用一句话说清状态含义,转移方程就有了着落。
排除法:C 选行号与输入输出切换的人把程序概念当成了算法概念;D 选数组大小与循环次数的人把工程参数当成了设计核心;B 选最终答案与打印语句的人完全没抓住「子问题」这层。
DP 的初始化(边界值)的作用是( )。
考点:初始化的意义(A3)。
(A3)考点:初始化的意义——给最小子问题直接赋答案,让转移有起点。
解析:本题考查初始化的意义。转移方程自底向上推导,最底层(如 、)无法再分解,必须人工给定;初始化就是这些「地基值」。地基错了,上面的楼层全部白搭(P3 展示后果)。
排除法:B 选清零当装饰的人不了解边界值直接参与转移;A 选代替转移方程的人把地基当成了整栋楼;C 选保证答案是零的人把手段误当成了结果。
动态规划与贪心法的本质区别是( )。
考点:DP 与贪心(A4)。
(A4)考点:DP 与贪心——贪心局部选择不回头,DP 综合全部子问题保证全局最优。
解析:本题考查 DP 与贪心。贪心快而险:每步只看眼前,可能错过更优组合(01 背包就是反例,C7);DP 慢而稳:枚举每个子问题的所有决策,答案有保证。两者复杂度常常一个是线性一个是多项式。
排除法:D 选贪心更慢的人把快慢关系弄反——贪心通常更快;A 选 DP 不能求最大值的人忘了背包、LIS 全是求最大值的 DP;B 选完全相同的人忽略了「是否考虑全部决策」这道分水岭。
DP 与递推的关系,最准确的说法是( )。
考点:DP 与递推(A5)。
(A5)考点:DP 与递推——递推是填表机制,DP 是带着最优或计数目标的递推应用。
解析:本题考查 DP 与递推。 是递推式;给它装上「爬楼梯方案数」的含义,它就成了 DP。可以说 DP 是递推的一种目标化使用:先设计状态含义,再找递推关系。
排除法:D 选毫无关系的人没看到公式形态完全一致;B 选方向固定的人把个别写法当成了本质,两者方向都随状态依赖而定;A 选只是改名的人忽略了 DP 的重心在「状态设计与最优性」,不只是套公式。
写一道 DP 题的标准流程依次是( )。
考点:DP 的四步(A6)。
(A6)考点:DP 的四步——定义状态、写转移方程、定初始化与边界、定计算顺序。
解析:本题考查 DP 的四步。顺序有讲究:先想清楚「一格装什么」,转移才有的放矢;初始化与边界和状态定义绑定;顺序保证被依赖的先算。本卷各代码题都是这四步的展开。
排除法:D 选写代码调试提交优化的人描述的是做题流程不是 DP 设计流程;C 选读题输出查格式的人连算法都没碰;B 选排序二分贪心输出的人把别的算法的口诀错安过来。
一个问题能用 DP 求解,需要的两个关键性质是( )。
考点:最优子结构与无后效性(A7)。
(A7)考点:最优子结构与无后效性——大问题最优解含子问题最优解;状态之后的过程不受到达路径影响。
解析:本题考查最优子结构与无后效性。前者保证「合并子问题答案」合法,后者保证「同一状态殊途同归」——不管怎么到 ,之后的决策只看 。两条都满足,dp 表才存得住通用答案。
排除法:B 选有序与互不相同的人把排序类前提错安过来;D 选数据范围限制的人把工程约束当数学性质;A 选必须求最大值的人忘了路径计数这类非最值 DP 同样适用。
爬楼梯每次上 或 阶,走到第 阶的方案数 满足( )。
考点:爬楼梯的 DP 视角(B1)。
(B1)考点:爬楼梯的 DP 视角——最后一步分类:。
解析:本题考查爬楼梯的 DP 视角。到达第 阶的最后一步只有两种:从 跨一阶、从 跨两阶;两类互不重叠且穷尽所有可能,方案数相加。这是「按最后一步分类」的最经典入门转移,真题也考过它的费用版(I7、2024-J阅21)。
排除法:A 选乘 的人没注意两类方案规模不同不可倍乘;B 选加 的人把「新增一种」误当「新增一批」;D 选 的人给出的恰是另一问题的答案(错排步数之类),与方案数无关。
最大子段和的状态设计 表示( )。
考点:最大子段和(B2)。
(B2)考点:最大子段和——f[i] 是以 i 结尾的最大子段和,答案扫全表取最大。
解析:本题考查最大子段和。状态定义带「以 i 结尾」是关键:它让 与 有了明确衔接关系(接上去或另起);答案不在 而在全表最大值(G3)。这两点是子段类 DP 的通用设计。
排除法:B 选前 个总和的人描述的是前缀和;D 选整段最大值的人丢掉了子段结构;C 选「前 i 个里任意子段最大」的人把状态含义说得过宽——那样转移写不出来。
数字三角形求从顶到底最大路径和,状态 通常定义为( )。
考点:数字三角形的状态(B3)。
(B3)考点:数字三角形的状态——f[i][j] 是到该点(或从该点到底)的最优累计。
解析:本题考查数字三角形的状态。两个方向都行:自顶向下 是「走到这的最大和」,自底向上是「从这到底部的最大和」;后者边界简单(最后一行就是自己),是更常用的写法(M 组)。
排除法:B 选数字本身的人把输入当成了状态;A 选前 行总和的人丢掉了路径结构;D 选路径条数的人把最值问题换成了计数问题,两者是不同的目标量。
网格只向右或向下走,从左上角到右下角的路径数,转移方程是( )。
考点:路径计数(B4)。
(B4)考点:路径计数——f[i][j] = f[i-1][j] + f[i][j-1],方案数相加。
解析:本题考查路径计数。到 的最后一步要么从上要么从左,两路方案互斥且穷尽,相加即得。计数 DP 与最值 DP 骨架相同,只是把 换成 、把「选最大」换成「条条都算」。 网格答案 (I4)。
排除法:C 选相乘的人没注意两条路不是独立组合而是并列来源;B 选取对角线的人把走法限制弄错(不允许斜走);D 选 的人给的公式与真实计数无关。
从一列数中取若干个,要求任意两个取出的数在原序列中不相邻,求取出的数之和最大。状态 应定义为( )。
考点:不相邻取数(B5)。
(B5)考点:不相邻取数——f[i] 讨论第 i 个取或不取。
解析:本题考查不相邻取数。状态定为「前 个数的最大和」,转移分两支:不取第 个,答案承袭;取第 个,则第 个不能取,从更早的 ()衔接。I5 是它的完整代码。
排除法:A 选前 个总和的人没考虑取或不取的抉择;C 选第 个数本身的人状态退化成输入;D 选前 个最大值的人丢掉了不相邻约束。
爬台阶每阶有一个花费,每次可跨 或 阶,可从第 或 阶起跳,求到达顶部的最小花费。转移应取( )。
考点:台阶最小花费(B6)。
(B6)考点:台阶最小花费——f[i] = min(f[i-1]+cost[i-1], f[i-2]+cost[i-2])。
解析:本题考查台阶最小花费。爬楼梯方案数把 换成 、再给每步贴上费用标签,就是本题:比较「从上一阶跨来」与「从上上阶跳来」谁更省。I7 实测 起跳规则下答案 ;2024 年阅读真题正是这一模型。
排除法:B 选只一步步爬的人漏了跨两阶的分支;A 选只比较两级费用的人丢掉了历史累积;C 选两式相加的人把方案数转移错安到最值问题上。
最长上升子序列(LIS)指的是( )。
考点:LIS 的定义(B7)。
(B7)考点:LIS 的定义——保持相对顺序、不要求连续的严格递增最长子序列。
解析:本题考查 LIS 的定义。三个要点:挑出的元素保持原相对顺序(可以跳着挑)、严格递增()、目标最长。与「最长连续上升段」的区别见 E5/P6——初学最易混。
排除法:C 选连续递增片段的人描述的是上升子段;D 选排序后长度的人丢掉了「子序列保持原序」的前提,排序会打乱次序;B 选最大最小差的人把序的结构简化成了两个数。
当 只依赖 与 时,可以用两三个变量滚动代替整个数组,其依据是( )。
考点:一维滚动优化(B8)。
(B8)考点:一维滚动优化——只依赖近几项时用变量交替保存。
解析:本题考查一维滚动优化。 只看 、,更早的值再也不会被引用;两个变量像接力棒一样滚动即可(I6 的 55)。省内存的本质是「历史无用」,不是玄学加速。
排除法:A 选更快得多的人把省内存错当提速——少掉的主要是空间;B 选数组溢出的人搞反了因果,滚动是主动选择不是被迫;D 选答案变大的人把存储优化与数值变化混为一谈。
01 背包( 件物品,每件最多选一次,容量 )的状态 通常定义为( )。
考点:01 背包状态定义(C1)。
(C1)考点:01 背包状态定义——f[i][j] 是前 i 件、容量不超 j 的最大价值。
解析:本题考查 01 背包状态定义。「前 件」+「容量 」两个维度把「选了哪些」的全部关键信息压缩进下标;每件最多选一次是 01 的含义。滚动成一维后 隐含了「当前考虑过前若干件」。
排除法:C 选总重量的人丢掉了价值维度;D 选物品数的人丢掉了容量维度;B 选第 件价值的人把状态退化成了输入。
01 背包的转移方程 ,其中两项分别表示( )。
考点:01 背包转移方程(C2)。
(C2)考点:01 背包转移方程——不选承袭 f[i-1][j],选则腾容量加价值。
解析:本题考查 01 背包转移方程。每件物品只有两种决策:不选,答案与「前 件、容量 」相同;选,要先在容量里腾出 (用 )再得 。两者取 ,决策完备。
排除法:A 选两项写反的人没逐项翻译 max 的两个参数;B 选两件不同物品的人下标里根本没有第二个物品的影子;C 选循环变量的人把语义参数当成了循环控制。
一维 01 背包的容量循环必须从大到小(倒序),原因是( )。
考点:容量循环必须倒序(C3)。
(C3)考点:容量循环必须倒序——倒序读旧值,正序同件反复计入。
解析:本题考查容量循环必须倒序。一维滚动时 与 同住一数组:倒序先算大容量,读 时它还是「没考虑第 件」的旧值;正序先算小容量,同一件物品会被计入多次(K2 实测 变 ),变成完全背包。
排除法:D 选更快的人把正确性需求错记成性能优化;B 选编译错误的人高估了编译器——运行正常但答案错;C 选自动扩容的人给循环方向安了不相干的职能。
要求背包「恰好装满」容量 时的最大价值,初始化应写成( )。
考点:恰好装满的初始化(C4)。
(C4)考点:恰好装满的初始化——f[0]=0,其余负无穷标记不可达。
解析:本题考查恰好装满的初始化。只有空包(容量 )天然可达且价值为 ;其余容量「还没装出来」要用负无穷表示不可达。转移照常取 ,负无穷天然被合法值压制;终态若仍是负无穷即无解(K7)。
排除法:C 选全 的人让「装不满」免费合法化,会报出错误价值(P3 实测);D 选正无穷的人把方向完全弄反,max 会优先选无穷;A 选 的人看似标记,但 参与加法会污染数值( 可能赢过合法值),必须用足够小的负数。
若只要求「总重量不超过 」的最大价值,初始化应为( )。
考点:不超过容量的初始化(C5)。
(C5)考点:不超过容量的初始化——全部为 0,空包即合法。
解析:本题考查不超过容量的初始化。「不超 」的语义下,任何容量都允许「什么都不装」,价值 是合法起点,全 初始化正确。恰好装满与不超容量的差别全部落在初始化一行上,转移一模一样。
排除法:D 选负无穷初始化的人把恰好装满的规矩错搬过来——不超容量问题里空包处处合法、从价值 起步;A 选正无穷的人方向就错, 会一路选中无穷;C 选随机初始化的人拿程序的确定性开玩笑——初值必须全部确定为 才能保证答案确定。
统计「恰好用满容量」的装法数,转移方程是( )。
考点:背包方案数转移(C6)。
(C6)考点:背包方案数转移——f[j] += f[j-w[i]](倒序),f[0]=1。
解析:本题考查背包方案数转移。方案数 DP 把最值的 换成 :到容量 的方案 = 不选第 件的旧方案 + 选第 件的方案 。 表示「什么都不装」恰是一种方案。K4 实测 装 得 。
排除法:A 选取 max 的人把计数问题当成了最值问题;B 选加一的人没注意新增的是「一整批」方案而非一个;D 选乘权重的人给方案数安了不相干的运算。
为什么 01 背包不能按「单位价值最高先装」的贪心做( )。
考点:01 背包与贪心(C7)。
(C7)考点:01 背包与贪心——不可分割使贪心失灵,DP 全决策枚举有保证。
解析:本题考查 01 背包与贪心。贪心按单位价值先装可能被「块头」卡住:大块占容量后,更划算的小件组合装不下。反例随手可造,DP 对每件「选/不选」全枚举,才保证最优。
排除法:C 选贪心永不对的人言过其实——部分背包(可分割)贪心恰恰正确;B 选单位价值溢出的人把数值细节当成了本质障碍;A 选代码长短的人把工程量当成了正确性依据。
网格类问题的二维状态 一般表示( )。
考点:二维状态设计(D1)。
(D1)考点:二维状态设计——f[i][j] 是到格子 (i,j) 的目标量。
解析:本题考查二维状态设计。网格两个坐标天然对应两维下标,状态含义挂上目标量(最大和、最小费、路径数)即可。它与「前 件容量 」的背包一样,都是「两个自由度各占一维」的设计。
排除法:C 选原始数值的人把输入当状态;A 选矩形总和的人描述的是二维前缀和;D 选剩余容量的人把背包语境错搬到网格。
矩阵每格有一个数,从左上角走到右下角(只右/下),求路径数字和最大。转移为( )。
考点:矩阵最大路径和(D2)。
(D2)考点:矩阵最大路径和——f[i][j] = max(上, 左) + a[i][j]。
解析:本题考查矩阵最大路径和。只右/下走, 的最优必经上方或左方,取较优者加上本格值。L1 实测 {{1,2,3},{4,5,6},{7,8,9}} 得 (贴着左边与底边走)。
排除法:B 选取 min 的人求成了最小路径;C 选对角线来源的人多加了斜走的非法路径;A 选 f[i-1][j-1] 的人跳过了中间必经的格子。
「只向右或向下走」的二维 DP,格子 的答案来自( )。
考点:二维转移来源(D3)。
(D3)考点:二维转移来源——只右/下走时来自上方与左方。
解析:本题考查二维转移来源。「反向看最后一步」:能走到 的前一步只可能在 (向下走)或 (向右走)。来源集合由移动规则决定,规则变(可斜走)来源就变。
排除法:B 选下方右方的人把方向整个弄反,那是「从终点往回走」的视角却还按正向依赖写;A 选四周相邻的人没注意不允许向上、向左;D 选仅对角线的人又虚构了斜走。
二维路径 DP 中首行与首列要单独初始化,原因是( )。
考点:边界行与列(D4)。
(D4)考点:边界行与列——首行首列单来源,需单独初始化。
解析:本题考查边界行与列。首行每格只能从左邻到达,首列只能从上邻到达,双来源转移在边界上会引用不存在的格;干脆按单来源规则直接累加初始化(L2 的 1 3 6)。
排除法:D 选数据最大的人把边界与数值扯在一起;B 选编译错误的人高估了检查,越界读的是垃圾值照样运行;C 选必须置零的人把「初始化」简单化成了清零,首行首列恰恰要累加。
网格中有障碍格(不可通行)时,路径计数 DP 的处理方式是( )。
考点:障碍物的处理(D5)。
(D5)考点:障碍物的处理——障碍格 f 置 0,其余照常累加。
解析:本题考查障碍物的处理。路径数为 表示「没有任何路径经过此格」,自动阻断后续格从它取数;转移公式完全不用改,只在循环里加一个障碍判断。L3 实测中心障碍后 。
排除法:A 选跳过不循环的人漏掉的格子还有后续格子依赖它,跳过会读到未初始化值;B 选正无穷的人在计数问题里显然荒谬;D 选平均值的人给计数安了不存在的运算。
网格、每格转移 的二维 DP,时间复杂度是( )。
考点:二维 DP 的复杂度(D6)。
(D6)考点:二维 DP 的复杂度——状态数 mn 乘单格转移 O(1)。
解析:本题考查二维 DP 的复杂度。 个状态每格只比两个来源,总时间 、空间同为 (可滚动到 )。复杂度口诀「状态数 × 单状态转移代价」在一切 DP 上通用。
排除法:D 选 的人只数了边界长度;A 选带对数的人给单格转移虚加了排序代价;B 选 的人忘了表本身要逐格填。
当 只依赖本行与上一行时,可以把二维数组压成一维,其原理是( )。
考点:二维滚动优化(D7)。
(D7)考点:二维滚动优化——逐行算,上一行用完即弃。
解析:本题考查二维滚动优化。 只依赖 与本行左侧,算完一行后上上行彻底无用,一维数组滚动保存最近一行即可(L4 展开「旧 恰是上一行」的对位关系)。空间从 降到 。
排除法:D 选必然更快的人又把省空间当提速;A 选必须压缩的人把优化选项说成了强制;C 选能算更大答案的人把内存与数值范围混为一谈。
最长上升子序列中「上升」指严格递增()。若允许相等(),得到的是( )。
考点:LIS 的严格性(E1)。
(E1)考点:LIS 的严格性——允许相等即最长不下降子序列。
解析:本题考查 LIS 的严格性。判断条件 (严格)与 (不下降)一词之差决定相等元素能否并列入选;J3 实测 不下降得 (1 2 2 4)。读题认清「上升/不下降」是第一步。
排除法:A 选最长下降的人把不等号方向改了而不是放宽;B 选无区别的人没算过 这类数据——严格 LIS 为 、不下降为 ;C 选公共子序列的人跳到了另一个双序列问题。
LIS 的转移方程 ( 且 )中, 表示( )。
考点:LIS 的转移方程(E2)。
(E2)考点:LIS 的转移方程——f[i] 是以 a[i] 结尾的 LIS 长度。
解析:本题考查 LIS 的转移方程。「以 结尾」让 与所有 有了明确的衔接条件( 时接上);初值 (自己单选)。与最大子段和同属「结尾型」设计。
排除法:A 选「前 i 个的 LIS」的人写不出转移——不知道结尾是谁就没法接龙;D 选上升对数的人把计数目标错当长度;B 选排名的人把序结构错当 DP 值。
按「结尾」定义算完所有 后,LIS 的最终答案是( )。
考点:LIS 的答案位置(E3)。
(E3)考点:LIS 的答案位置——扫全部 f[i] 取最大,结尾任意。
解析:本题考查 LIS 的答案位置。「以 i 结尾」的定义不保证最长链恰在末项结束(结尾可能在任何位置),答案取 。对比「前 i 个」型定义答案在 ——状态定义决定取答案的位置(G3)。
排除法:A 选 的人给 这类数据立刻翻车(最长链 结尾在下标 , 只是 );C 选 的人假设最长链必含首项,不成立;D 选平均值的人把离散结构当成了统计量。
要输出 LIS 的具体序列(不只是长度),标准做法是( )。
考点:LIS 的序列还原(E4)。
(E4)考点:LIS 的序列还原——转移时记 pre[i],从结尾回溯。
解析:本题考查 LIS 的序列还原。 记录 的最优来源 ;找到答案结尾后沿 一路走回开头,倒序输出即还原序列。J5 实测 还原 2 5 7。「带 pre 回溯」适用于一切要输出方案的 DP。
排除法:B 选直接输出 f 的人输出的是长度表不是序列;A 选无法还原的人低估了记录来源的威力;D 选排序输出的人把原序丢掉,子序列定义就不成立了。
「子序列」与「子段」的区别是( )。
考点:子序列与子段(E5)。
(E5)考点:子序列与子段——子序列可不连续,子段必须连续。
解析:本题考查子序列与子段。LIS、LCS 是子序列问题(跳着挑),最大子段和是子段问题(连续一段);两者转移结构不同——子段型与相邻格衔接,子序列型可从任意更早的格衔接。混用概念是 P6 的错误根源。
排除法:A 选两者相同的人没做过 :LIS 为 而最长上升子段只有 ;C 选定义互换的人正好弄反;B 选只能取一半的人给子序列加了不存在的限制。
LIS 长度可能由多条不同的子序列达到。统计方案数时,转移遇到 应执行( )。
考点:LIS 的多条方案(E6)。
(E6)考点:LIS 的多条方案——同长时方案相加,更长时覆盖重置。
解析:本题考查 LIS 的多条方案。 说明又发现一条等长来源,; 说明更长链出现,覆盖 并重置 。O3 实测 得长度 方案 。
排除法:C 选直接覆盖的人丢掉了等长的其他来源;A 选取最大的人把计数当最值;B 选清零的人在恰好该累加的时候清了账。
DP 与分治都划分子问题,关键差别是( )。
考点:DP 与分治(F1)。
(F1)考点:DP 与分治——分治子问题独立,DP 子问题重叠需记录。
解析:本题考查 DP 与分治。归并排序左右两半互不相干(独立),算完即弃;DP 的子问题被反复用到(如斐波那契的 会被多条路径依赖),不记录就重复计算、指数爆炸。重叠与独立是两种划分方式的分水岭。
排除法:C 选只能分两半的人把常见形态当成了定义,DP 状态可有任意依赖;B 选 DP 不能递归的人忘了记忆化搜索就是递归 DP;D 选分治不做最优问题的人没见过归并求逆序对等应用。
回溯枚举所有方案与 DP 求最优的对比,正确的是( )。
考点:DP 与回溯(F2)。
(F2)考点:DP 与回溯——回溯全枚举指数级,DP 记录共享多项式。
解析:本题考查 DP 与回溯。全排列式回溯把每条路走到黑,路径数指数增长;DP 发现「走到同一状态之后的答案相同」,算一次存表共享。「记录换枚举」是 DP 的灵魂,也是它能多项式求解的原因。
排除法:D 选回溯总是更快的人把指数级当成了快;A 选循环写法代价相同的人没理解共享子问题带来的量级差异;C 选都不能计数的人忘了路径计数 DP 恰是计数利器。
DP 的时间复杂度通常按( )估算。
考点:DP 的复杂度估算(F3)。
(F3)考点:DP 的复杂度估算——状态总数乘单状态转移代价。
解析:本题考查 DP 的复杂度估算。LIS: 个状态、每状态内层 ,总 ;01 背包: 状态、 转移,总 。先数状态维度的乘积,再看每个状态要比较多少来源。
排除法:A 选数组大小的人只看了空间没看每格工作量;C 选输入位数的人把位运算的度量错安过来;D 选答案大小的人把输出量当成了计算量。
「求最长的简单路径」不能直接 DP,因为( )。
考点:最优子结构反例(F4)。
(F4)考点:最优子结构反例——最长简单路径的局部最优拼不出全局最优。
解析:本题考查最优子结构反例。图上「 到 的最长路」若取「 到中途点的最长」再拼尾巴,尾巴可能途经前段用过的点,简单路径条件被破坏——子问题最优不能保证组合合法。所以它不能直接 DP(问题在提高级另有解法,初赛知道反例即可)。
排除法:B 选数组存不下的人把工程限制当数学障碍;A 选必须连通的人没抓住要害,连通图照样反例;D 选「无最优子结构的问题不存在」的人把教科书级反例(最长简单路径)当成了不存在。
初学 DP 最常见的三类错误是( )。
考点:DP 的常见错误(F5)。
(F5)考点:DP 的常见错误——状态模糊、转移漏决策、边界不当。
解析:本题考查 DP 的常见错误。三大高发区:状态说不清(一句定义都写不出)、转移漏分支(如背包漏「不选」、H3)、初始化错位(恰好装满错用全零、P3)。改错先按 A6 四步自查,再用 G6 打表定位。
排除法:B 选语法类错误(分号头文件)的人描述的是编程入门坑不是 DP 特有坑;C 选命名注释的人把代码风格当成了算法错误;D 选输入输出样例的人把环境问题当成了设计问题。
设计 DP 状态时的「三问」是( )。
考点:状态设计三问(G1)。
(G1)考点:状态设计三问——这格是哪个子问题、怎么推出来、地基是什么。
解析:本题考查状态设计三问。三问分别对应状态定义、转移方程、初始化——A6 四步的前三步浓缩成可自问的口诀。设计卡壳时按三问顺序过一遍,通常卡在第一问。
排除法:A 选数组大小循环层数的人谈的是实现细节不是设计;B 选数据组数样例时限的人谈的是比赛环境;D 选排序去重递归循环的人谈的是别的算法的工具箱。
DP 循环顺序的确定原则是( )。
考点:转移顺序(G2)。
(G2)考点:转移顺序——被依赖的先算。
解析:本题考查转移顺序。 依赖更小下标就从小到大;数字三角形自底向上时依赖更大行号,就从最后一行往上。顺序由依赖方向决定,不是死记「从小到大」——倒序依赖倒着算(背包的容量维同理)。
排除法:D 选一律从小到大双层循环的人在三角形、背包的容量维上立刻翻车;B 选顺序无所谓的人没遇到过读未初始化格的教训;A 选从答案倒算一遍的人把「输出路径回溯」错当成了「计算顺序」。
DP 算完后「去哪里取答案」,正确的认识是( )。
考点:答案的位置(G3)。
(G3)考点:答案的位置——结尾型扫全表,前缀型取 f[n]。
解析:本题考查答案的位置。「以 结尾」型(最大子段和、LIS)答案取 ;「前 个」型(爬楼梯、背包)答案看 或 。取答案的位置由状态定义决定,写完代码先核对这一处。
排除法:C 选永远在 的人会被 LIS 打脸(H4);A 选永远在 的人方向整个反了;B 选最后被赋值处的人把程序行为当成了设计依据。
DP 数组的大小应按( )开。
考点:DP 数组的大小(G4)。
(G4)考点:DP 数组的大小——按状态定义开并给边界留位。
解析:本题考查 DP 数组的大小。 从 起时开 ;背包按容量开 。多留一两格放 这类边界比压着开更安全——越界是阴沟里翻船(P5)。
排除法:C 选越大越好的人内存会被大样例教做人;D 选固定开 的人在千级数据上立刻爆;B 选等于答案值的人把两个不相干的量绑在了一起。
转移中 、 这类下标计算要保证( )。
考点:下标边界处理(G5)。
(G5)考点:下标边界处理——循环条件拦住负下标与超界。
解析:本题考查下标边界处理。、 这类约束写进循环边界(背包 j >= w[i])或条件表达式(网格的三目判断),保证每次访存合法。边界处理与 G4 的数组大小配合,构成 DP 代码的安全网。
排除法:C 选越界无所谓的人把未定义行为当成了运气;A 选全部加一的人平移下标、避开下标 的特判,能躲一部分问题但边界判断仍少不了;D 选开小数组防越界的人把防护做成了自杀。
DP 调试的首选手段是( )。
考点:打印 DP 表调试(G6)。
(G6)考点:打印 DP 表调试——与手算小样例逐格核对。
解析:本题考查打印 DP 表调试。小规模样例先手算整张表,程序打印后逐格比对,第一个不一致的格就是错误转移的现场——比盯着代码空想快一个数量级。M2 的 DP 表输出就是这种调试的直接产物。
排除法:C 选盯代码的人效率最低且最容易漏;B 选提交碰运气的人在考场上没有运气可碰;A 选换 long long 的人把类型问题当成了万能药。
一维 01 背包把容量循环写成正序,直接后果是( )。
考点:背包正序的错误(H1)。
(H1)考点:背包正序的错误——同一物品反复计入,变成完全背包。
解析:本题考查背包正序的错误。正序时小容量先更新,同一轮里 已经计入过第 件, 再引用它就把这件数了第二遍。K2 用真题级数据实测倒序 、正序 ;「正序=完全背包」这一巧合正是 C3 的原理复用。
排除法:A 选程序崩溃的人高估了故障形态——它安静地给错答案;C 选只算第一件的人没追踪后续轮次,全部物品都在被重复选;B 选输出恒为 的人没看到转移确实在更新数值。
「恰好装满」问题把 全初始化为 ,后果是( )。
考点:初始化错误(H2)。
(H2)考点:初始化错误——恰好装满错用全零,装不满被合法化。
解析:本题考查初始化错误。全零初始化下每个容量都「免费可达」,装不满的状态带着 价值参与 max,可能压过真实可达的小价值方案。P3 实测一件 、:正确模型应报不可达,错初始化报 。
排除法:A 选编译错误的人又把逻辑错当语法错;B 选死循环的人把初始化与循环条件混为一谈;D 选没有影响的人没算过恰好装满与不超容量两版答案的差别。
转移方程漏写「不选第 件」的分支(只保留选的分支),后果是( )。
考点:转移漏选(H3)。
(H3)考点:转移漏选——漏「不选」分支即被迫全选。
解析:本题考查转移漏选。背包每件有两个决策,max 里两项各管一个;漏掉「不选」()一项,等于强制每件必选——总重随时可能爆容量,答案自然错。转移必须覆盖决策全集。
排除法:C 选等价原方程的人没注意少了一个 max 分支;D 选只影响速度的人没发现答案都变了;B 选数组溢出的人把语义错误错报成内存错误。
LIS 算完后误把 (最后一项结尾的值)当成答案,可能出错的原因是( )。
考点:LIS 答案取错(H4)。
(H4)考点:LIS 答案取错——f[n] 不是答案,结尾型要扫全表。
解析:本题考查 LIS 答案取错。 的最长链是 ,结尾在下标 ,而 (以 结尾)只是 ——取 直接错。正确做法取 。状态定义(E2)与取答案位置(G3)要配套检查。
排除法:C 选「 一定是 」的人换了个错法, 有值但未必最大;B 选「数组乱序」的人把实现细节当成了设计缺陷;D 选「只能从第一项开头」的人给 LIS 加了不存在的限制。
关于动态规划,下列说法正确的是( )。
考点:DP 综合判断(H5)。
(H5)考点:DP 综合判断——每子问题只算一次,记录换时间。
解析:本题考查 DP 综合判断。DP 表保证每个子问题恰好计算一次,重叠子问题由「查表」代替「重算」——这是它对比暴力枚举的本质优势。其余选项的错误各自对应一条常见误解。
排除法:D 选必须递归的人忘了迭代填表同样正统;A 选任何问题都有多项式 DP 的人高估了它的疆域——TSP 之类至今没有多项式解法;B 选转移与循环顺序无关的人没读过 G2。
01int f[20]; 02f[1] = 1; f[2] = 2; 03for (int i = 3; i <= 5; i++) 04 f[i] = f[i - 1] + f[i - 2]; 05cout << f[5];
输出是( )。
考点:爬楼梯方案数(I1)。
(I1)考点:爬楼梯方案数——f[1]=1、f[2]=2 起步填到 f[5]=8。
解析:本题考查爬楼梯方案数。、、——斐波那契数列换了身衣服。方案数转移「末步分类相加」,从两个地基值一路推到目标。
排除法:C 答 的人停在 ;D 答 的人多推一步到了 ;B 答 的人中途加错一次。
01int a[] = {-2, 3, -1, 2, -5}; 02int f[5]; 03f[0] = a[0]; 04for (int i = 1; i < 5; i++) 05 f[i] = max(f[i - 1] + a[i], a[i]); 06int mx = f[0]; 07for (int i = 1; i < 5; i++) mx = max(mx, f[i]); 08cout << mx;
输出是( )。
考点:最大子段和输出(I2)。
(I2)考点:最大子段和输出——{-2,3,-1,2,-5} 的答案是 4。
解析:本题考查最大子段和输出。逐格算:,最大 (子段 )。注意负前缀被 及时丢弃,这是「另起炉灶」分支的功劳。
排除法:A 答 的人只算了首格;D 答 的人把 当成了连续子段,中间隔着 ;B 答 的人漏了 后还能接 。
01// 三角形:7 / 3 8 / 8 1 0 / 2 7 4 4 02int f[4][4]; 03for (int j = 0; j < 4; j++) f[3][j] = tri[3][j]; 04for (int i = 2; i >= 0; i--) 05 for (int j = 0; j <= i; j++) 06 f[i][j] = tri[i][j] + max(f[i + 1][j], f[i + 1][j + 1]); 07cout << f[0][0];
输出是( )。
考点:数字三角形最大路径(I3)。
(I3)考点:数字三角形最大路径——经典 7/3 8/8 1 0/2 7 4 4 三角形答案 25。
解析:本题考查数字三角形最大路径。自底向上逐行取大:底层照抄;第三层 、、;第二层 、;顶层 。路径为 。
排除法:C 答 的人把更大的三角形经典数据记串了;B 答 的人某层取小时算错;A 答 的人只输出顶层数字。
01int f[3][3]; 02f[0][0] = 1; 03for (int i = 0; i < 3; i++) 04 for (int j = 0; j < 3; j++) { 05 if (i == 0 && j == 0) continue; 06 int up = (i > 0) ? f[i - 1][j] : 0; 07 int lf = (j > 0) ? f[i][j - 1] : 0; 08 f[i][j] = up + lf; 09 } 10cout << f[2][2];
输出是( )。
考点:网格路径计数(I4)。
(I4)考点:网格路径计数——3x3 网格右下角路径数 6。
解析:本题考查网格路径计数。表逐格填:,右下角 ——恰是 (四步中选两步向下)。计数转移把每格两路来源相加。
排除法:D 答 的人以为等于格子数;B 答 的人只数了单调走法的一半;C 答 的人把来源相加了两次。
01int a[] = {3, 1, 4, 1, 5}; 02int f[5]; 03for (int i = 0; i < 5; i++) { 04 f[i] = a[i]; 05 for (int j = 0; j + 2 <= i; j++) 06 f[i] = max(f[i], f[j] + a[i]); 07} 08int mx = 0; 09for (int i = 0; i < 5; i++) mx = max(mx, f[i]); 10cout << mx;
输出是( )。
考点:不相邻取数(I5)。
(I5)考点:不相邻取数——{3,1,4,1,5} 不相邻最大和 12。
解析:本题考查不相邻取数。最优取 (下标 两两隔开)和为 。逐格算 ( 从 取到最大)。约束「隔至少一个」在转移上表现为只能衔接 的来源。
排除法:A 答 的人把 之类的相邻项也算进去;B 答 的人取的 ? 或 少拿了一个可取的;C 答 的人只取了单个最大值。
01int a = 1, b = 1; 02for (int i = 3; i <= 10; i++) { 03 int c = a + b; 04 a = b; 05 b = c; 06} 07cout << b;
输出是( )。
考点:斐波那契滚动(I6)。
(I6)考点:斐波那契滚动——两变量滚到第 10 项 55。
解析:本题考查斐波那契滚动。 起步:——第 项 。变量 像接力棒轮转,历史值自然丢弃,是 B8 滚动思想的四行实现。
排除法:A 答 的人少滚一轮;C 答 的人多滚一轮;D 答 的人把项数当成了值。
01// cost[] = {10, 15, 20},从第 0 或 1 阶起跳,每次跨 1 或 2 阶,跳离时支付该阶费用 02int f[4]; 03f[0] = 0; 04f[1] = cost[0]; 05for (int i = 2; i <= 3; i++) 06 f[i] = min(f[i - 1] + cost[i - 1], f[i - 2] + cost[i - 2]); 07cout << f[3];
输出是( )。
考点:台阶最小花费(I7)。
(I7)考点:台阶最小花费——{10,15,20} 从 0 或 1 起跳、跳离付费模型下 f[3]=25。
解析:本题考查台阶最小花费。(从 起跳付 );(走 );(走 付 )。模型关键:付费发生在「跳离」时。2024 年阅读真题即此模型。
排除法:A 答 的人只算了起跳费用没算两跳;C 答 的人走了 全程付 ,比 贵;D 答 的人把三段费用全加。
01int a[] = {3, 1, 4, 1, 5, 9, 2, 6}; 02int f[8]; 03for (int i = 0; i < 8; i++) { 04 f[i] = 1; 05 for (int j = 0; j < i; j++) 06 if (a[j] < a[i]) f[i] = max(f[i], f[j] + 1); 07} 08int mx = 0; 09for (int i = 0; i < 8; i++) mx = max(mx, f[i]); 10cout << mx;
输出是( )。
考点:LIS 的长度(J1)。
(J1)考点:LIS 的长度——{3,1,4,1,5,9,2,6} 的 LIS 为 4。
解析:本题考查 LIS 的长度。最长链如 或 ,长度 。双循环 逐格比较前驱取最大;答案扫全表。
排除法:B 答 的人以为整个序列都递增,两个 已破坏严格性;D 答 的人把不合法的链(含相等或降序对)也数了进去;C 答 的人漏了更长的链。
01int a[] = {1, 3, 2, 4}; 02int f[4]; 03for (int i = 0; i < 4; i++) { 04 f[i] = 1; 05 for (int j = 0; j < i; j++) 06 if (a[j] < a[i]) f[i] = max(f[i], f[j] + 1); 07} 08for (int i = 0; i < 4; i++) cout << f[i] << " ";
输出是( )。
考点:f 数组的值(J2)。
(J2)考点:f 数组的值——{1,3,2,4} 的 f 为 1 2 2 3。
解析:本题考查 f 数组的值。逐格算:( 单选);();(,接 );( 或 )。输出 1 2 2 3——f 表本身就是理解 LIS 转移的最佳教具。
排除法:B 答 1 1 2 2 的人对 接错来源;C 答 1 2 3 4 的人以为 f 记录的是元素值或位置;A 答 1 2 2 4 的人末格把元素值 当成了长度。
01// a = {1, 3, 2, 2, 4},判断条件用 a[j] <= a[i] 02int f[5]; 03for (int i = 0; i < 5; i++) { 04 f[i] = 1; 05 for (int j = 0; j < i; j++) 06 if (a[j] <= a[i]) f[i] = max(f[i], f[j] + 1); 07} 08// 输出 f 的最大值
输出是( )。
考点:最长不下降(J3)。
(J3)考点:最长不下降——{1,3,2,2,4} 用 <= 得 4。
解析:本题考查最长不下降。条件放宽为 后,两个 可并列入选:链 长度 。与严格版差在一个等号,读题审「上升/不下降」就是审这个等号。
排除法:C 答 的人还在用严格版口径;B 答 的人以为全序列都合法, 到 是下降;D 答 的人低估了链长。
01// a = {5, 3, 4, 2, 1},判断条件用 a[j] > a[i] 02int f[5]; 03for (int i = 0; i < 5; i++) { 04 f[i] = 1; 05 for (int j = 0; j < i; j++) 06 if (a[j] > a[i]) f[i] = max(f[i], f[j] + 1); 07} 08// 输出 f 的最大值
输出是( )。
考点:最长下降(J4)。
(J4)考点:最长下降——{5,3,4,2,1} 把小于换成大于得 4。
解析:本题考查最长下降。条件 让链往低处走: 或 ,长度 。LIS 家族(上升/不上升/下降/不下降)全靠不等号方向与开闭调节。
排除法:C 答 的人漏了 或 这一层;B 答 的人以为 这对升序也能入选;A 答 的人只看首尾两个数。
序列 a = {2, 5, 3, 7} 求 LIS 时记录了来源数组 pre = {-1, 0, -1, 1}(pre[i] 是 f[i] 的最优来源下标,无来源记 ),最长链的结尾在下标 。沿 pre 回溯收集元素,还原出的 LIS 是( )。
考点:LIS 序列还原(J5)。
(J5)考点:LIS 序列还原——{2,5,3,7} 沿 pre 回溯得 2 5 7。
解析:本题考查 LIS 序列还原。、:答案结尾下标 (),沿 走 ,收集 倒序输出 2 5 7。pre 记录的是「最优来源」,回溯路径就是一条最优链。
排除法:A 答 2 3 7 的人回溯时走错了来源(下标 的 是 ,不是 的来源);B 答 5 7 的人回溯提前停了一步;C 答 2 5 3 7 的人把整条原序列当成了 LIS。
对序列 {1, -2, 3, 4, -1} 分别求:最长严格上升子序列长度、最大子段和,两个结果分别是( )。
考点:LIS 与子段对比(J6)。
(J6)考点:LIS 与子段对比——{1,-2,3,4,-1} 的 LIS 是 3、最大子段和是 7。
解析:本题考查 LIS 与子段对比。LIS 取 长度 ;最大子段和取连续段 和为 ( 后另起炉灶)。一个挑元素可跳、一个必须连续,同一段数据两个问题互不干扰。
排除法:B 答 与 的人把子段 的和算成了长度;C 答 与 的人把 塞进了上升链;D 答 与 的人以为两种口径都取全序列长度。
01// w = {2, 3, 4, 5}, v = {3, 4, 5, 6}, C = 8 02int f[9]; 03memset(f, 0, sizeof(f)); 04for (int i = 0; i < 4; i++) 05 for (int j = 8; j >= w[i]; j--) 06 f[j] = max(f[j], f[j - w[i]] + v[i]); 07cout << f[8];
输出是( )。
考点:01 背包最大价值(K1)。
(K1)考点:01 背包最大价值——w={2,3,4,5}、v={3,4,5,6}、C=8 的答案是 10。
解析:本题考查 01 背包最大价值。最优组合为第 、 件(、)。四层循环逐件倒序更新,。这也是后续 K2/K5/K6 共用的基准数据。
排除法:C 答 的人选了 却把价值加成了 之类的错值;A 答 的人把全部价值相加没管容量;D 答 的人差在没找到 恰好 的最优组合。
01// w = {2, 3, 4, 5}, v = {3, 4, 5, 6}, C = 8 02int f[9]; 03memset(f, 0, sizeof(f)); 04for (int i = 0; i < 4; i++) 05 for (int j = w[i]; j <= 8; j++) // 容量循环误写成正序 06 f[j] = max(f[j], f[j - w[i]] + v[i]); 07cout << f[8];
结果是( )。
考点:正序循环的错误输出(K2)。
(K2)考点:正序循环的错误输出——同数据正序得 12。
解析:本题考查正序循环的错误输出。正序让同一件物品反复入包:第 件()可装两次得 ,再配第 件()共 ?实测逐轮核:最终 (完全背包口径的 组合,价值 经脚本验证为 )。结论不变:正序=可重复选。
排除法:A 答 的人以为答案不变,重复选取真实发生了;C 答 的人以为程序报错,转移照常执行;D 选死循环的人把逻辑错误错报成了卡死。
物品重量 w = {2, 3, 4}、价值 v = {3, 4, 5}、容量 。恰好装满模型下 、其余 初值为负无穷(不可达标记),标准 01 背包倒序转移后输出 ,结果是( )。
考点:恰好装满的价值(K3)。
(K3)考点:恰好装满的价值——{2,3,4} 装 C=5 得 7。
解析:本题考查恰好装满的价值。恰好 的唯一组合是 ,价值 ;负无穷初始化保证「装不满」的容量不会贡献假价值。
排除法:D 答 的人把 与 全装( 超容);B 答 的人以为装不满报零,负无穷口径下装得满就有值;C 答 的人把容量当成了价值。
01// w = {1, 2, 3},统计恰好装满容量 3 的方案数 02int f[4]; 03memset(f, 0, sizeof(f)); 04f[0] = 1; 05for (int i = 0; i < 3; i++) 06 for (int j = 3; j >= w[i]; j--) 07 f[j] += f[j - w[i]]; 08cout << f[3];
输出是( )。
考点:恰好装满的方案数(K4)。
(K4)考点:恰好装满的方案数——{1,2,3} 装 3 有 2 种。
解析:本题考查恰好装满的方案数。组合 与 各恰好占满容量 ,共 种。 起步、倒序累加,与最值版只差一个运算符。
排除法:A 答 的人漏了 ;B 答 的人把 ( 超容)或 (重复选)也算了进去;D 答 的人按排列数而非组合数计数。
一维滚动背包 f[j] = max(f[j], f[j-w[i]] + v[i])(倒序)与二维表版的关系是( )。
考点:滚动数组版(K5)。
(K5)考点:滚动数组版——一维倒序与二维表逐行等价。
解析:本题考查滚动数组版。二维 只看上一行;一维滚动把两行叠进同一数组,倒序保证读 时拿到的是「上一行」的旧值。K1 与 K6 两版输出同为 ,殊途同归。
排除法:D 选不同算法的人没看出两者转移式逐字对应;C 选少了不选分支的人没注意 第一项就是不选;B 选必须递归的人把实现形式错当成了算法要求。
01// w = {2, 3, 4, 5}, v = {3, 4, 5, 6}, C = 8 02int f[5][9]; 03memset(f, 0, sizeof(f)); 04for (int i = 1; i <= 4; i++) 05 for (int j = 0; j <= 8; j++) { 06 f[i][j] = f[i - 1][j]; 07 if (j >= w[i - 1]) 08 f[i][j] = max(f[i][j], f[i - 1][j - w[i - 1]] + v[i - 1]); 09 } 10cout << f[4][8];
输出是( )。
考点:二维表版(K6)。
(K6)考点:二维表版——f[4][8] 同样是 10。
解析:本题考查二维表版。二维表逐件逐容量填, 与滚动版一致。二维版的好处:表可打印、好调试(G6),且不依赖倒序的技巧——教学时先二维后一维最稳。
排除法:D 答 的人某格忘了「不选」承袭分支;A 答 的人把价值求和没管容量;C 答 的人输出成了物品数。
物品重量 w = {2, 3},恰好装满模型(,其余初值负无穷),容量 ,标准倒序转移后检查 ,其状态是( )。
考点:不可达的判断(K7)。
(K7)考点:不可达的判断——w={2,3} 装 C=1 不可达。
解析:本题考查不可达的判断。两件物品重量都大于 ,容量 的负无穷标记原样保留——正确语义是「无解」而非「价值为零」。输出前判 是否仍为负无穷,是恰好装满题的收尾动作。
排除法:C 答 的人把「不可达」当成了「零价值装法」;B 答 的人把容量当成了价值;D 答 的人把物品重量当成了答案。
01// 矩阵 a = {{1,2,3},{4,5,6},{7,8,9}},从左上角只右/下走到右下角 02int f[3][3]; 03f[0][0] = a[0][0]; 04for (int j = 1; j < 3; j++) f[0][j] = f[0][j - 1] + a[0][j]; 05for (int i = 1; i < 3; i++) f[i][0] = f[i - 1][0] + a[i][0]; 06for (int i = 1; i < 3; i++) 07 for (int j = 1; j < 3; j++) 08 f[i][j] = max(f[i - 1][j], f[i][j - 1]) + a[i][j]; 09cout << f[2][2];
输出是( )。
考点:矩阵最大路径和(L1)。
(L1)考点:矩阵最大路径和——1..9 矩阵最大路径 29。
解析:本题考查矩阵最大路径和。最优路径 沿左边与底边走,和 。双来源转移每格取较大前驱,。
排除法:C 答 的人走了 的边线但算错或选错边;D 答 的人把矩阵总和当成了路径;A 答 的人取了对角线 。
矩阵 a = {{1,2,3},{4,5,6},{7,8,9}},从左上角只右/下走的路径 DP。按边界初始化代码 f[0][j] = f[0][j-1] + a[0][j] 计算后,首行 f[0][0..2] 三个值是( )。
考点:边界行输出(L2)。
(L2)考点:边界行输出——首行前缀 1 3 6。
解析:本题考查边界行输出。首行只能从左累加:、、——首行的 DP 表就是行前缀和,单来源结构一目了然。
排除法:C 答 1 2 3 的人没做累加直接抄了原数据;D 答 1 4 10 的人算成了列方向的累加;B 答 6 3 1 的人把顺序倒放。
01// 3x3 网格,(1,1) 为障碍(不可通行),f[障碍] = 0 02f[0][0] = 1; 03for (int i = 0; i < 3; i++) 04 for (int j = 0; j < 3; j++) { 05 if (i == 0 && j == 0) continue; 06 if (bad[i][j]) { f[i][j] = 0; continue; } 07 f[i][j] = (i > 0 ? f[i - 1][j] : 0) + (j > 0 ? f[i][j - 1] : 0); 08 } 09cout << f[2][2];
输出是( )。
考点:障碍物路径数(L3)。
(L3)考点:障碍物路径数——中心障碍后右下角为 2。
解析:本题考查障碍物路径数。障碍 置 :表为 ——绕过中心的上下两条边路各贡献 ,右下角共 。置零即阻断,转移不必特判。
排除法:A 答 的人忘了障碍阻断;D 答 的人多算了一次阻断(把 或 也当障碍);B 答 的人以为障碍切断了所有路,上下边路仍通。
二维路径 DP 压成一维滚动数组逐行计算时,第 行第 列的更新要用到( )。
考点:逐行滚动版(L4)。
(L4)考点:逐行滚动版——旧 f[j] 是上一行、新 f[j-1] 是本行左邻。
解析:本题考查逐行滚动版。从左到右更新第 行时: 尚未更新,装的还是上一行同列; 刚更新过,已是本行左邻——两路来源恰好齐备。滚动版正是靠「更新先后」区分了两行。
排除法:A 选更新前的 的人把左邻也当成了上一行,丢了本行来源;D 选 系的人方向与依赖全错;B 选无法计算的人低估了滚动技巧的对位精度。
同 L1 矩阵 {{1,2,3},{4,5,6},{7,8,9}} 的最大路径 DP,全部算完后 的值是( )。
考点:打印二维 DP 表(L5)。
(L5)考点:打印二维 DP 表——f[1][1] 是 10。
解析:本题考查打印二维 DP 表。中心格 的两个来源:上方 累计 、左方 累计 ;取较优的 加本格 得 ,最优路 。
排除法:A 答 的人把首列前缀和 错当中心格值;B 答 的人输出成了原始数据;C 答 的人取了 这条较逊的路,没有比较两个来源。
矩阵最大路径和的转移横线处应填( )。
01int a[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; 02int f[3][3]; 03f[0][0] = a[0][0]; 04for (int i = 0; i < 3; i++) 05 for (int j = 0; j < 3; j++) { 06 if (i == 0 && j == 0) continue; 07 f[i][j] = ______ + a[i][j]; 08 }
考点:二维转移补全(L6)。
(L6)考点:二维转移补全——填 max(f[i-1][j], f[i][j-1])。
解析:本题考查二维转移补全。最大路径和的双来源取大:上格与左格中较优者接上本格。 是最小路径(M4 主题)、对角来源是非法走法、两格相加会把两条路重复计量。
排除法:D 选 min 的人把目标从最大改成了最小;A 选 的人引入了不存在的斜走;B 选相加的人把「二选一」写成了「全都要」。
数字三角形 7 / 3 8 / 8 1 0 / 2 7 4 4 自底向上 DP, 的值是( )。
考点:自底向上求值(M1)。
(M1)考点:自底向上求值——第三层首格 8+max(2,7)=15。
解析:本题考查自底向上求值。自底向上转移 :第三层首格取底层 与 的较大者 ,加本格 得 。逐层向上直到塔尖得 (I3)。
排除法:A 答 的人只算了本格没加子结点;C 答 的人取了较小的子结点 ;D 答 的人把两个子结点都加上了,转移是二选一不是全取。
数字三角形 7 / 3 8 / 8 1 0 / 2 7 4 4 自底向上 DP 算完后, 与 分别是( )。
考点:自底向上 DP 表(M2)。
(M2)考点:自底向上 DP 表——第二层是 18 与 16。
解析:本题考查自底向上 DP 表。第三层算好 后,第二层:、。打印整张表逐层核对(G6 调试法),第三层的 与顶层的 联成完整证据链。
排除法:A 答 与 的人输出成了原始数据;B 答 与 的人把左右顺序弄反;C 答 与 的人把顶层与第二层混在一起。
数字三角形记录最优路径,转移时应( )。
考点:路径记录(M3)。
(M3)考点:路径记录——转移分支上记走向,最后从顶走到底。
解析:本题考查路径记录。在 取到左子或右子的分支处,同步记下「走左/走右」;塔尖算完后从 沿记录逐层下行,输出 这条最优路径。与 LIS 的 pre 回溯(E4)同宗:记录来源、事后回放。
排除法:D 选排序三角形的人把数据结构整个破坏;C 选无法记录的人低估了分支标记的作用;A 选每次清空记录的人恰恰要在转移时保留记录。
数字三角形 7 / 3 8 / 8 1 0 / 2 7 4 4,把自底向上转移中的 max 换成 min(求最小路径和),结果是( )。
考点:最小路径和(M4)。
(M4)考点:最小路径和——同一三角形换 min 得 15。
解析:本题考查最小路径和。转移把 换成 :第三层 、、;第二层 、;顶层 。最小路径为 。
排除法:A 答 的人忘了换 沿用最大路径;C 答 的人某层取小算错一格;D 答 的人只算了部分层数。
自底向上数字三角形的转移横线处应填( )。
01int tri[4][4] = {{7}, {3, 8}, {8, 1, 0}, {2, 7, 4, 4}}; 02int f[4][4]; 03for (int j = 0; j < 4; j++) f[3][j] = tri[3][j]; 04for (int i = 2; i >= 0; i--) 05 for (int j = 0; j <= i; j++) 06 f[i][j] = tri[i][j] + ______;
考点:转移方程补全(M5)。
(M5)考点:转移方程补全——自底向上填 max(f[i+1][j], f[i+1][j+1])。
解析:本题考查转移方程补全。自底向上的依赖在下一行(),来源是正下与右下两格取大。填 方向的人依赖反了(那是自顶向下的写法且还要防 越界);两格相加的人把二选一写成全取;取 的人把目标换成了最小路径。
排除法:C 选 max(f[i-1][j], f[i-1][j-1]) 的人方向与自底向上矛盾;B 选相加的人重复计量两条路;A 选 min(f[i][j], ...) 的人把「本格」卷进了比较,转移对象错位。
补全爬楼梯方案数的转移:
01int f[20]; 02f[1] = 1; f[2] = 2; 03for (int i = 3; i <= n; i++) 04 f[i] = /* 1 */;
空位 /* 1 */ 处应填( )。
考点:补全爬楼梯转移(N1)。
(N1)考点:补全爬楼梯转移——填 f[i-1] + f[i-2]。
解析:本题考查补全爬楼梯转移。末步分类两条来源相加:跨一阶的 与跨两阶的 。乘 的选项把两类规模不同的方案当成对称;加一的选项把「新增一类」误当「新增一个」。
排除法:C 填乘 的人没注意 与 数值不同;B 填 f[i] + 1 的人自引用且语义不明;A 填 f[i-1] + 1 的人丢掉了跨两阶的来源。
补全 LIS 的内层转移:
01int f[N]; 02for (int i = 0; i < n; i++) { 03 f[i] = 1; 04 for (int j = 0; j < i; j++) 05 if (a[j] < a[i]) 06 f[i] = /* 1 */; 07}
空位 /* 1 */ 处应填( )。
考点:补全 LIS 转移(N2)。
(N2)考点:补全 LIS 转移——填 max(f[i], f[j] + 1)。
解析:本题考查补全 LIS 转移。max 的第一项保住「已有的更长链」不被更短来源覆盖;直接写 会在遍历多个 时被后来的短链冲掉。这是「转移要覆盖全部决策」的细节体现。
排除法:C 填 f[j] + 1 的人丢掉了与当前值比较的守护项;A 填 min 的人方向全反;D 填相加的人把计数运算错安进长度问题。
补全一维 01 背包的容量循环:
01for (int i = 0; i < n; i++) 02 for (int j = C; /* 1 */; j--) 03 f[j] = max(f[j], f[j - w[i]] + v[i]);
空位 /* 1 */ 处应填( )。
考点:补全背包倒序(N3)。
(N3)考点:补全背包倒序——循环条件填 j >= w[i]。
解析:本题考查补全背包倒序。倒序 for (j = C; j >= w[i]; j--) 的下界 同时完成两件事:保证 不越界、装不下的容量根本不用更新(G5)。填 会读到负下标。
排除法:B 填 j >= 0 的人会在 时越界;A 填 j > w[i] 的人恰好漏掉 的「单独装这件」;C 填 j <= C 的人把循环方向条件写反,循环根本不按预期走。
补全自底向上数字三角形的行循环(4 行三角形):
01for (int j = 0; j < 4; j++) f[3][j] = tri[3][j]; 02for (int i = /* 1 */; i >= 0; i--) 03 for (int j = 0; j <= i; j++) 04 f[i][j] = tri[i][j] + max(f[i + 1][j], f[i + 1][j + 1]);
空位 /* 1 */ 处应填( )。
考点:补全数字三角形(N4)。
(N4)考点:补全数字三角形——外层起始填 2。
解析:本题考查补全数字三角形。四层三角形自底向上:底层()已作边界赋值,转移从 开始递减到 。填 会把底层再算一遍并引用不存在的第五行;填 或 则高层先算、依赖未就绪。
排除法:D 填 的人让边界行错误地依赖不存在的行;B 填 的人方向对了起点错,读到未初始化的下方格;A 填 的人漏算了第二层。
补全网格路径计数的转移:
01for (int i = 0; i < m; i++) 02 for (int j = 0; j < n; j++) { 03 if (i == 0 && j == 0) { f[i][j] = 1; continue; } 04 f[i][j] = /* 1 */; 05 }
空位 /* 1 */ 处应填( )。
考点:补全二维转移(N5)。
(N5)考点:补全二维转移——三目判断守住边界来源。
解析:本题考查补全二维转移。(i > 0 ? f[i-1][j] : 0) + (j > 0 ? f[i][j-1] : 0) 在边界处自动把不存在的来源记 。直接写两格相加在首行首列会越界;三目写法把 D4 的「单独初始化」内联进了转移,两种风格等价。
排除法:A 填裸相加的人没处理边界越界;C 填对角来源的人虚构斜走;D 填乘 的人把并列来源错当倍增。
「恰好装满」背包的初始化横线处应填( )。
01const int NEG = -1e9; 02f[0] = 0; 03for (int j = 1; j <= C; j++) 04 f[j] = /* 1 */;
考点:补全恰好装满初始化(N6)。
(N6)考点:补全恰好装满初始化——非零容量填 NEG。
解析:本题考查补全恰好装满初始化。 之外全部负无穷(NEG),表示「尚未找到任何恰好装满的方案」。转移取 max 时负无穷天然不敌任何合法值,终态负无穷即无解(C4、K7)。
排除法:B 填 的人让装不满免费合法(P3 后果);D 填 的人方向反了,max 会一路选中无穷;C 填 的人的标记会参与加法污染数值, 可能假赢合法值。
补全网格路径计数的边界初始化(首行):
01f[0][0] = 1; 02for (int j = 1; j < n; j++) 03 f[0][j] = /* 1 */;
空位 /* 1 */ 处应填( )。
考点:补全路径计数(N7)。
(N7)考点:补全路径计数——首行初始化填 f[0][j-1]。
解析:本题考查补全路径计数。首行每格只能从左邻到达,方案数逐格承袭(全部为 )——单来源链式传递。这与 L2 首行前缀和同构:边界初始化就是「只有一个来源时的简化转移」。
排除法:B 填两来源相加的人在首行引用了不存在的上一行;A 填 的人把坐标值当成了方案数;C 填 1 + f[0][j] 的人自引用且方向不明。
w = {1, 2, 3},容量 。「恰好装满的最大价值」(价值等于重量)与「恰好装满的方案数」分别是( )。
考点:背包与方案数综合(O1)。
(O1)考点:背包与方案数综合——{1,2,3} 装 C=3 价值 3、方案 2。
解析:本题考查背包与方案数综合。价值取重量时恰好装满的最优就是装满本身:价值 ;组合 与 两方案。同一套循环换个聚合运算(max 或加),最值与计数一鱼两吃。
排除法:D 答 与 的人多算了一个方案( 与 之外没有恰好 的组合);C 答 与 的人把价值当成了可重复选( 是 超容);B 答 与 的人漏了 。
数字三角形各行为 7、3 -8、8 1 0、2 -7 4 4(含负数),自底向上按 max 转移算完输出 ,结果是( )。
考点:数字三角形含负数(O2)。
(O2)考点:数字三角形含负数——7/3 -8/8 1 0/2 -7 4 4 的最大路径 20。
解析:本题考查数字三角形含负数。DP 对负数一视同仁:第三层 、、;第二层 、;顶层 。负数不必特判,转移照常取优。
排除法:D 答 的人照抄了全正数三角形的旧答案;A 答 的人某层比较出错;C 答 的人在第二层取了错误的分支。
序列 a = {1, 3, 2},同时统计 LIS 的长度与达到该长度的方案数,两个结果分别是( )。
考点:LIS 与方案计数(O3)。
(O3)考点:LIS 与方案计数——{1,3,2} 长度 2 方案 2。
解析:本题考查 LIS 与方案计数。: 由 (链 )、 由 (链 );长度最大值 ,达到该长度的结尾有两个,方案数 。E6 的「等长相加、更长重置」在此完整落地。
排除法:B 答 与 的人只数了一个结尾的方案;A 答 与 的人以为全序列严格递增, 到 是下降;C 答 与 的人把长度与方案数两个量对调了。
矩阵 {{1,2,3},{4,5,6},{7,8,9}} 最大路径 DP 中, 的值是( )(右下角左邻格)。
考点:矩阵最大路径综合(O4)。
(O4)考点:矩阵最大路径综合——f[2][1] 是 20。
解析:本题考查矩阵最大路径综合。到 的两路: 与 ,取 (路径 )。它与 、 一起构成整张表的抽样核对点。
排除法:D 答 的人走了 (和 )或加错一格;A 答 的人把 错当 ;C 答 的人漏加了某格。
w = {2, 3},容量 ,恰好装满模型( 其余负无穷,价值等于重量),标准倒序转移后 的值是( )。
考点:恰好装满综合(O5)。
(O5)考点:恰好装满综合——w={2,3} 装 C=4 不可达。
解析:本题考查恰好装满综合。两件各选一次的全部组合: 差 、 差 、 超出——没有任何组合恰好 , 保持负无穷(输出时判无解)。负无穷标记的价值在终态检查时兑现(K7 同型)。
排除法:A 答 的人以为 可行,但同件物品在 01 背包只能选一次;B 答 的人把「最接近的装法」当成了恰好装满;D 答 的人报出了半装状态的价值。
下列说法正确的是( )。
考点:DP 综合判断(P1)。
(P1)考点:DP 综合判断——状态设计不唯一,自洽即可。
解析:本题考查 DP 综合判断。爬楼梯可按「末步分类」也可按「首步分类」;背包可「前 i 件」也可「考虑后 i 件」——殊途同归。判据是状态含义、转移、初始化三者自洽,而不是与某个「标准答案」长得一样。
排除法:A 选只有一种标准答案的人把教学示例当成了教条;D 选每格都装最终答案的人忘了格子里装的是子问题答案;C 选转移不许有条件判断的人没见过背包的容量判断、LIS 的比较条件——条件判断无处不在。
01// w = {2, 3}, v = {3, 4}, C = 4,f 全 0 起步 02for (int i = 0; i < 2; i++) 03 for (int j = w[i]; j <= 4; j++) // 正序(错误示范) 04 f[j] = max(f[j], f[j - w[i]] + v[i]); 05cout << f[4];
输出是( )。
考点:正序循环错误输出(P2)。
(P2)考点:正序循环错误输出——w={2,3}、v={3,4}、C=4 正序得 6。
解析:本题考查正序循环错误输出。第 件()正序反复入包:、max(0,;第 件更新不超过它。输出 ——容量 装了两次第 件(,价值 ),完全背包口径;倒序正确版同数据答案为 (单装第 件)。
排除法:D 答 的人给的是倒序正确版的答案,没注意本题循环写成了正序;A 答 的人只装了一件第 件漏了重复;B 答 的人以为程序报错,转移照常执行。
01// w = {2}, v = {5}, C = 4,恰好装满模型却误把 f 全部初始化为 0 02for (int i = 0; i < 1; i++) 03 for (int j = 4; j >= w[i]; j--) 04 f[j] = max(f[j], f[j - w[i]] + v[i]); 05cout << f[4];
输出是( )。
考点:初始化错误输出(P3)。
(P3)考点:初始化错误输出——全零初始化下装不满也报出 5。
解析:本题考查初始化错误输出。,全零起步倒序转移: 时 尚为 ,故 ;随后 得 。终值 ——正确恰好装满模型里容量 应不可达,错误初始化让「半装状态」把价值传了上去。
排除法:B 答 的人以为装不满就报零,max 链把价值传到了 ;A 答 的人以为 先更新再被引用,倒序先算大容量、 当时还是 ;C 答 的人给了正确模型的输出,本题问的恰是错误初始化报出 的后果。
最大子段和转移误写成 f[i] = f[i - 1] + a[i](丢掉 max(..., a[i])),对 a = {-3, 5} 的影响是( )。
考点:覆盖式转移错误(P4)。
(P4)考点:覆盖式转移错误——丢 max(..., a[i]) 后 {-3,5} 从 5 错成 2。
解析:本题考查覆盖式转移错误。正确转移 允许「放弃负前缀、从本格另起」;写成 后 ,丢掉了单选 的更优解。子段 DP 的「另起炉灶」分支一条都不能少。
排除法:C 选结果总相同的人遇到任何负前缀数据立刻翻车;D 选覆盖式更大的人方向反了——覆盖式只会更小或相等;B 选无法运行的人又把逻辑错当运行错。
一维背包循环写成 for (int j = 0; j <= C; j++) f[j] = max(f[j], f[j - w[i]] + v[i]);,其中的错误是( )。
考点:容量下标越界(P5)。
(P5)考点:容量下标越界——j < w[i] 时 j-w[i] 为负。
解析:本题考查容量下标越界。循环条件 j >= w[i] 同时承担「装得下才考虑」与「下标不越界」两个职责;写成 j >= 0 后, 会取到 、 等负下标,读数组前的内存。C++ 不拦负下标——未定义行为静默发生。
排除法:C 选方向错但不越界的人没注意负下标正是越界;A 选只是效率低的人低估了后果;D 选开两倍大的人修错了地方——负下标在数组前面,开大后面无济于事。
把「最长上升子序列」误做成「最长连续上升段」,对 a = {5, 1, 2, 0, 3} 的结果是( )。
考点:连续与不连续混淆(P6)。
(P6)考点:连续与不连续混淆——{5,1,2,0,3} 连续段 2、LIS 3。
解析:本题考查连续与不连续混淆。最长连续上升段是 (长度 );LIS 是 (跳过 ,长度 )。子序列允许跳跃,子段不许——两个问题的转移结构也不同:子段型衔接相邻格,子序列型可衔接任意更早的格。
排除法:C 选两者都是 的人没算连续段( 打断了 与 );A 选都是 的人低估了 LIS;D 选连续段是 的人以为整段都上升, 到 第一步就降。