判断题:动态规划(DP)= 把问题拆成子问题、每个子问题只算一次并记录,由小到大组合出答案——适用前提是最优子结构 + 重叠子问题。
考点:DP 的定义(A1)。
解析:DP = 拆子问题 + 每个子问题只算一次并记录 + 由小到大组合——前提是最优子结构与重叠子问题。✅ 正确
排除法:无(判断题)。混淆点:没有重叠子问题时直接分治/递推即可,DP 的"记录"没有收益。
关联 · 最优子结构的反例(F5):前提不满足时 DP 失效。
判断题:DP 的三要素:状态(f 数组表示什么)、转移(怎么由小状态算出大状态)、初始化(最小状态的初值)。
考点:状态与转移(A2)。
解析:DP 三要素:状态(f 表示什么)、转移(怎么算)、初始化(初值)——写 DP 前先把这三样写清楚。✅ 正确
排除法:无(判断题)。混淆点:状态定义模糊是 DP 题最大的坑(P5 的教训)。
关联 · DP 的四步(A6):三要素 + 答案位置 = 完整流程。
判断题:初始化错误会让整张 DP 表错——例如"恰好装满"的背包没有把"不可达容量"设成 ,就会把非法状态当合法。
考点:初始化(A3)。
解析:"恰好装满"要设不可达(),"不超过"全 0——初始化错误整张表都错(H2/P2)。✅ 正确
排除法:无(判断题)。混淆点:初值不是"拍脑袋",由状态语义决定。
关联 · 恰好装满的初始化(C4):背包的初始化是最经典案例。
判断题:贪心每步只做一个选择;DP 尝试所有转移取最优——DP 更"全面",但要求状态能编号、转移满足无后效性。
考点:DP 与贪心(A4)。
解析:贪心锁定一个选择,DP 枚举所有转移取最优——DP 更全面但要求状态可编号、无后效。✅ 正确
排除法:无(判断题)。混淆点:能用贪心的问题通常 DP 也能做(更慢);反之不行。
关联 · 零一背包与贪心(C7):贪心失效、DP 成功的典型。
判断题:递推是 DP 的雏形:DP 的"状态 + 转移"就是递推的"数组 + 公式",DP 多了"取 max/min 的最优决策"。
考点:DP 与递推(A5)。
解析:递推 = DP 的雏形:状态+转移 = 数组+公式,DP 多出"取最优决策"。✅ 正确
排除法:无(判断题)。混淆点:斐波那契/爬楼梯既是递推也是 DP——边界模糊但本质同源。
关联 · 递推的滚动变量(第 14 章 C5):一维 DP 常配滚动优化。
判断题:做 DP 的标准四步:① 定义状态 ② 写转移方程 ③ 定初始化 ④ 找答案位置。
考点:DP 的四步(A6)。
解析:定义状态 → 写转移 → 定初始化 → 找答案——四步缺一不可。✅ 正确
排除法:无(判断题)。混淆点:答案位置常被忽略(G3/H4)。
关联 · 状态设计三问(G1):第一步怎么做好。
单选题:爬楼梯 ,、。 的值是?
考点:爬楼梯的 DP 视角(B1)。
解析:。正确答案 A。
排除法:B()是 ;C()是 ;D()是 。
关联 · 爬楼梯递推输出(第 14 章 K2):递推与 DP 同源。
判断题:最大子段和的一维 DP:f[i] = max(f[i-1] + a[i], a[i])——"接在前一段后面"或"以 a[i] 重新开始"。
考点:最大子段和的 DP(B2)。
解析:f[i] = max(f[i-1] + a[i], a[i])——"接上"或"重新开始"两种决策取 max。✅ 正确
排除法:无(判断题)。混淆点:与 LIS 的区别——子段必须连续(E5)。
关联 · 最大子段和的 DP 输出(I2):代码版输出 5。
单选题:数字三角形自顶向下走(每步左下或右下),第 行第 列的状态由上一行的哪两个状态转移而来?
考点:数字三角形的状态(B3)。
解析: 由上一行第 列(左上)和第 列(正上)转移而来。正确答案 A。
排除法:B 是自底向上的来源方向;C 同行不能转移;D 反了。
关联 · 自顶向下输出(M1):转移方程的代码。
判断题:网格从 只能向右/下走到 ,路径数 ,。
考点:路径计数的 DP(B4)。
解析:,——两个来源相加(组合计数)。✅ 正确
排除法:无(判断题)。混淆点:与数字三角形的"取 max"不同,计数是"相加"。
关联 · 路径计数 DP 输出(I4): 输出 6。
判断题:LIS(最长上升子序列)= 从序列中按原顺序选出、不必连续的最长严格递增子序列。
考点:LIS 的定义(B5)。
解析:LIS = 按原顺序选出、不必连续、严格递增的最长子序列。✅ 正确
排除法:无(判断题)。混淆点:"不必连续"是 LIS 与最大子段的关键区别(E5)。
关联 · LIS 的转移方程(E2):定义的 DP 化。
单选题:一排数选若干个数使和最大、且不能选相邻两个, 表示前 个数的最优解,转移是?
考点:不相邻取数(B6)。
解析:选 就必须跳过 → 。正确答案 A。
排除法:B 会连选相邻;C 相当于不选时也加了 ;D 漏了"不选"分支。
关联 · 不相邻取数(I5):代码版输出 15。
判断题:一维 DP 若 只依赖 、,可用滚动变量把空间从 降到 。
考点:一维 DP 的滚动优化(B7)。
解析:只依赖前两项 → 两个变量滚动,空间 。✅ 正确
排除法:无(判断题)。混淆点:滚动只省空间不省时间。
关联 · 斐波那契滚动 DP(I6):滚动代码。
单选题:01 背包( 件物品、重量 、价值 、容量 、每件最多选 1 次),状态 表示?
考点:01 背包的状态定义(C1)。
解析: = 前 件物品、容量 的最大总价值。正确答案 A。
排除法:B/C/D 都不是"状态"的定义。
关联 · 二维表版(K6):二维表代码。
单选题:01 背包对第 件物品(重量 、价值 )的转移是?
考点:01 背包的转移方程(C2)。
解析:选 = 、不选 = ,取 max。正确答案 A。
排除法:B 漏了不选分支;C 是别的模型;D 只写了选分支。
关联 · 转移漏选(H3):漏"不选"的后果。
判断题:滚动数组版 01 背包的容量循环必须倒序(j 从 到 )——正序会让同一件物品被选多次。
考点:容量循环必须倒序(C3)。
解析:倒序保证 是"上一件物品"的状态;正序会让本件物品被重复选。✅ 正确
排除法:无(判断题)。混淆点:二维表版不需要倒序(用 )。
关联 · 正序循环的错误输出(K2):单件物品正序输出 9。
判断题:"恰好装满"要求初始化 、其余为 (或极小值)——装不满的容量状态保持"不可达"。
考点:恰好装满的初始化(C4)。
解析:、其余 ——装不满的状态保持不可达,只有从 转移来的才合法。✅ 正确
排除法:无(判断题)。混淆点: 用 -1e9 之类极小值实现(N6)。
关联 · 初始化错误的输出(P2):全 0 初始化的错误结果。
判断题:"不超过容量"(装不满也算合法)时初始化全部为 即可。
考点:不超过容量的初始化(C5)。
解析:"不超过"时装不满合法 → 全 0 初始化。✅ 正确
排除法:无(判断题)。混淆点:两种初始化对应两种题目语义,别混(H2)。
关联 · 恰好装满的初始化(C4):一对镜像。
单选题:求"恰好装满容量 的方案数",滚动数组的转移是?
考点:背包方案数的转移(C6)。
解析:方案数用加法累积:f[j] += f[j-w](倒序保证不重选)。正确答案 A。
排除法:B 是最值转移;C/D 无依据。
关联 · 恰好装满的方案数(K4):代码版输出 3。
判断题:01 背包不能用贪心(按单位价值排序会错)——第 15 章的 0/1 背包反例正是 DP 的用武之地。
考点:零一背包与贪心(C7)。
解析:按单位价值贪心会错(第 15 章反例:贪 160 vs 最优 220)——01 背包必须 DP。✅ 正确
排除法:无(判断题)。混淆点:部分背包可贪、01 背包不可贪——"能不能分割"是关键。
关联 · 零一背包贪心结果(第 15 章 K5):反例代码。
判断题:二维 DP 的状态是 f[i][j]——"走到/处理到第 行第 列时……",常见于网格路径类问题。
考点:二维 DP 的状态(D1)。
解析:二维 DP 状态是 ——"走到/处理到第 行第 列时……",常见于网格路径问题。✅ 正确
排除法:无(判断题)。混淆点:一维 DP 状态是 (前缀),二维多一维坐标。
关联 · 数字三角形的状态(B3):二维状态的代表。
判断题: 矩阵从 到 只能向右/下走,最大路径和:。
考点:矩阵最大路径和(D2)。
解析:——从上方或左方来,取较大的。✅ 正确
排除法:无(判断题)。混淆点:计数用"相加"、最值用"取 max"——两类转移别混。
关联 · 矩阵最大路径和输出(L1):代码版输出 12。
单选题:矩阵路径 DP 中 由哪两个状态转移而来?
考点:二维转移的来源(D3)。
解析:只能右/下走 → 由上方 和左方 转移。正确答案 A。
排除法:B 是斜走模型;C 是倒走;D 是同行横向。
关联 · 边界行与列(D4):来源的边界处理。
判断题:矩阵路径 DP 中,第一行只能从左方来、第一列只能从上方来——边界行/列的转移要特判,否则会越界读状态。
考点:边界行与列(D4)。
解析:第一行只能从左来、第一列只能从上来——转移前先判 j > 0、i > 0,否则越界。✅ 正确
排除法:无(判断题)。混淆点:越界读 f[i-1][j] 是 DP 常见崩溃点(G5)。
关联 · 补全二维转移(N5):边界判断的代码。
判断题:有障碍的网格:计数 DP 中障碍格的路径数记为 (不可达),转移时跳过障碍格。
考点:障碍物的处理(D5)。
解析:障碍格路径数记 (不可达),转移跳过——计数 DP 的标准处理。✅ 正确
排除法:无(判断题)。混淆点:最值型障碍用"不可达"(极小值)而不是 0。
关联 · 障碍物路径数(L3):代码版输出 2。
单选题: 矩阵的二维 DP 时间复杂度是?
考点:二维 DP 的复杂度(D6)。
解析: 个格子各算一次、每次 转移 → 。正确答案 A。
排除法:B 是一维平方;C 是线性;D 是三重循环的量级。
关联 · DP 的复杂度估算(F3):状态数 × 转移代价。
判断题:二维 DP 可以逐行滚动:只保留上一行数组,空间从 降到 。
考点:二维 DP 的滚动优化(D7)。
解析:只依赖上一行 → 逐行滚动,空间 。✅ 正确
排除法:无(判断题)。混淆点:滚动时旧值会被覆盖,转移顺序要对(G2)。
关联 · 逐行滚动版(L4):滚动代码输出 8。
判断题:LIS 要求严格递增(转移条件 );把条件放宽为 就是最长不下降子序列(LNDS)。
考点:LIS 的严格性(E1)。
解析:严格递增用 ;不下降(允许相等)用 ——一个符号之差。✅ 正确
排除法:无(判断题)。混淆点:题目说"不下降/非降"时别用严格条件。
关联 · 最长不下降子序列(J3): 输出 4。
单选题:LIS 的 转移中, 的初值应是?
考点:LIS 的转移方程(E2)。
解析: 初值 (自己一个)——否则空序列长度为 0,答案全错。正确答案 A。
排除法:B()会让长度少 1;C 是序列长;D 是值。
关联 · LIS 的长度(J1):输出 4。
单选题:LIS 的长度是?
考点:LIS 的答案位置(E3)。
解析:最长子序列不一定以最后一个元素结尾 → 取 。正确答案 A。
排除法:B 在"以最后结尾"时才对;C/D 无依据。
关联 · LIS 答案取错(H4):易错点。
判断题:记录 pre[i]( 由哪个 转移来),从答案位置沿 pre 倒推,即可还原出一条 LIS。
考点:LIS 的序列还原(E4)。
解析:pre[i] 记录转移来源,从答案位置倒推还原。✅ 正确
排除法:无(判断题)。混淆点:多条 LIS 时还原出的是"按转移顺序找到的一条"。
关联 · LIS 的序列还原(J5):
2,1,5,3,4还原出2 3 4。
判断题:子序列不必连续(如 LIS),子段/子数组必须连续(如最大子段和)——两个概念要分清。
考点:子序列与子段(E5)。
解析:子序列不连续(LIS),子段连续(最大子段和)——概念要分清。✅ 正确
排除法:无(判断题)。混淆点:题目"子串/子数组/子段"都指连续,"子序列"不连续。
关联 · LIS 与子段对比(J6):
4 15双输出。
判断题:最长长度相同的 LIS 可能有多条(不同元素组成)——题目问方案时注意按规则去重。
考点:LIS 的多条方案(E6)。
解析:长度相同的 LIS 可能有多条( 与 ),计数注意去重规则。✅ 正确
排除法:无(判断题)。混淆点:方案计数用加法累积(O3)。
关联 · LIS 与方案计数(O3): 输出
3 2。
判断题:分治的子问题独立不重叠;DP 的子问题大量重叠——这是两者适用场景的分界。
考点:DP 与分治(F1)。
解析:分治子问题独立、DP 子问题重叠——重叠是"记录复用"的价值所在。✅ 正确
排除法:无(判断题)。混淆点:归并/快排是分治不是 DP(子问题不重叠)。
关联 · DP 的定义(A1):重叠子问题是前提之一。
判断题:回溯指数级枚举所有方案;DP 记录每个状态的最优值、避免重复计算——规模大时 DP 是回溯的"高效版"。
考点:DP 与回溯(F2)。
解析:回溯枚举所有方案(指数级),DP 记录状态最优(多项式级)——同一问题的两种强度。✅ 正确
排除法:无(判断题)。混淆点: 小可用回溯对拍验证 DP(F6)。
关联 · DP 与枚举(F6):对拍验证。
判断题:DP 的时间复杂度 = 状态数 × 每个状态的转移代价。
考点:DP 的复杂度估算(F3)。
解析:复杂度 = 状态数 × 转移代价——先估算再动手。✅ 正确
排除法:无(判断题)。混淆点:二维 DP = 状态 × 转移(D6)。
关联 · 二维 DP 的复杂度(D6):实例。
判断题:DP 常见错误:状态定义不清、转移漏分支(如漏"不选")、初始化错、答案位置取错。
考点:DP 的常见错误(F4)。
解析:状态不清、转移漏分支、初始化错、答案取错——四大坑。✅ 正确
排除法:无(判断题)。混淆点:四大坑对应 H 组四道易错题。
关联 · 打印 DP 表调试(G6):调试手段。
单选题:以下哪类问题不满足最优子结构(子问题最优拼不出全局最优)?
考点:最优子结构的反例(F5)。
解析:带环图最长简单路径:子路径最优拼不出全局最优(路径不能重复顶点)→ DP 失效。正确答案 A。
排除法:B/C/D 都满足最优子结构,DP 可解。
关联 · DP 的定义(A1):前提的边界。
判断题: 很小时可以用暴力枚举验证 DP 结果(对拍); 大时 DP 才是可行方案。
考点:DP 与枚举(F6)。
解析: 小暴力枚举对拍验证 DP; 大 DP 是可行方案。✅ 正确
排除法:无(判断题)。混淆点:对拍只能找反例、不能证明正确。
关联 · 用反例验证贪心(第 15 章 A6):同款验证哲学。
判断题:状态设计三问:状态装得下(数组够大)、转移要简单、答案要取得到。
考点:状态设计三问(G1)。
解析:装得下(数组大小)、转移简单、答案取得到——三问过一遍再写代码。✅ 正确
排除法:无(判断题)。混淆点:状态维度太多会超空间(G4)。
关联 · DP 数组的大小(G4):状态设计的边界。
判断题:转移顺序必须保证"用到的状态先算好"(拓扑序)——背包按容量从小到大、二维 DP 按行从上到下。
考点:转移顺序(G2)。
解析:用到的状态必须先算好:背包按容量从小到大、二维 DP 按行从上到下。✅ 正确
排除法:无(判断题)。混淆点:顺序错 = 用了"旧值"当"新值"。
关联 · 边界行与列(D4):顺序与边界的配合。
判断题:答案可能在 f[n][m]、max(f[n][*]) 或全部状态的最大值——按题目定义取。
考点:答案的位置(G3)。
解析:答案可能在某固定点、某一行、或全局最大——按题目定义取。✅ 正确
排除法:无(判断题)。混淆点:LIS 取 max 全体、背包取 f[n][C]、三角形取最后一行 max。
关联 · LIS 的答案位置(E3):位置随题变。
判断题:DP 数组要开"状态最大值 + 1"(防止下标越界),越界是 DP 题最常见的崩溃点之一。
考点:DP 数组的大小(G4)。
解析:开"状态最大值 + 1",越界是最常见的崩溃点。✅ 正确
排除法:无(判断题)。混淆点:下标从 1 起时数组多开一位(P4)。
关联 · 容量下标越界(P4):越界后果。
单选题:01 背包转移中当 j < w(容量放不下当前物品)时,应该?
考点:下标边界的处理(G5)。
解析:j < w 放不下 → 只走不选分支。正确答案 A。
排除法:B 会越界/错值;C 漏状态;D 无依据。
关联 · 容量下标越界(P4):边界判断的必要性。
判断题:调试 DP 的实用方法:打印整张 DP 表,与小数据手算结果对照,能快速定位状态/转移/初始化错误。
考点:打印 DP 表调试(G6)。
解析:打印整张 DP 表与手算对照——快速定位状态/转移/初始化错误。✅ 正确
排除法:无(判断题)。混淆点:打印表是"对拍"的弱化版,小数据手算 + 打印结合最有效。
关联 · 打印 DP 表(M5):三角形的最后一行
12 14 15。
单选题:滚动数组 01 背包把容量循环写成正序,后果是?
考点:背包正序的错误(H1)。
解析:正序让本件物品可被重复选(变成完全背包行为),答案偏大。正确答案 A。
排除法:B/C 错;D——偏大不是"恰好正确"。
关联 · 正序循环的错误输出(K2):单件物品输出 9 的实证。
单选题:"恰好装满"背包却用全 初始化,会?
考点:初始化错误(H2)。
解析:"恰好装满"却全 0 → 没装满的状态也"合法",答案可能偏大。正确答案 A。
排除法:B 错;C 方向反;D 不会崩。
关联 · 初始化错误的输出(P2):输出 5 而非 -1。
单选题:01 背包转移只写"选"分支、漏了"不选"分支,会?
考点:转移漏选(H3)。
解析:只写"选"漏"不选" → 某些最优解被丢掉,答案偏小。正确答案 A。
排除法:B 方向反;C 错;D 不会崩。
关联 · 覆盖式转移的错误输出(P3):漏不选的代码实证。
单选题:LIS 最长子序列不以最后一个元素结尾时,正确做法是?
考点:LIS 答案取错(H4)。
解析:LIS 不以最后元素结尾 → 必须取 。正确答案 A。
排除法:B 只在特殊数据成立;C/D 无依据。
关联 · LIS 的答案位置(E3):概念题代码化。
判断题:以下结论全部正确——"DP 三要素是状态/转移/初始化;01 背包滚动数组容量倒序;LIS 答案取最大值;数字三角形逐行填表"。
考点:DP 综合判断(H5)。
解析:四句全部正确:三要素、背包倒序、LIS 取 max、数字三角形逐行填表。✅ 正确
排除法:无(判断题)。混淆点:这是本章骨架,逐条对照各组题目。
关联 · DP 的四步(A6):本章总结。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int f[15]; 05 f[1] = 1; f[2] = 2; // 爬楼梯初始化 06 for (int i = 3; i <= 10; i++) 07 f[i] = f[i - 1] + f[i - 2]; // 转移 08 cout << f[10]; 09 return 0; 10}
单选题:程序输出是?
考点:爬楼梯 DP 输出(I1)。
解析:( 起逐项)。正确答案 A。
实现要点:一维 DP 框架 = 初始化 + 转移循环。手算:从 填到 。
排除法:B 是 ;C 是 ;D 是 。
关联 · 爬楼梯的 DP 视角(B1):概念题的代码版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[6] = {-2, 1, -3, 4, -1, 2}; 05 int f[6], best; 06 f[0] = a[0]; best = f[0]; 07 for (int i = 1; i < 6; i++) { 08 f[i] = max(f[i - 1] + a[i], a[i]); // 接上 / 重新开始 09 best = max(best, f[i]); 10 } 11 cout << best; // 最大子段和 12 return 0; 13}
单选题:程序输出是?
考点:最大子段和的 DP 输出(I2)。
解析:f[i] = max(f[i-1]+a[i], a[i]): → 最大 5。正确答案 A。
实现要点:DP 版 Kadane = "接上/重新开始"二选一;答案要取 max(f[*]) 而非 f[n-1]。手算:逐项填 f。
排除法:B(6)多数;C(4)漏尾段;D 无依据。
关联 · 最大子段和的 DP(B2):转移的代码。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[3][3] = {{3, 0, 0}, {1, 5, 0}, {8, 6, 7}}; // 3 层数字三角形 05 int f[3][3] = {0}; 06 f[0][0] = a[0][0]; 07 for (int i = 1; i < 3; i++) 08 for (int j = 0; j <= i; j++) { 09 f[i][j] = a[i][j]; 10 if (j > 0) f[i][j] = max(f[i][j], f[i - 1][j - 1] + a[i][j]); 11 if (j < i) f[i][j] = max(f[i][j], f[i - 1][j] + a[i][j]); 12 } 13 cout << max({f[2][0], f[2][1], f[2][2]}); // 最后一行最大值 14 return 0; 15}
单选题:程序输出是?
考点:数字三角形最大路径(I3)。
解析:。正确答案 A。
实现要点:三角形 DP = 二维 f 表 + 左上/正上双来源(注意 、 边界)。手算:逐行填表,最后一行取 max。
排除法:B(12)是 ;C(14)是 ;D(10)是 。
关联 · 数字三角形的状态(B3):转移方向。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int f[3][3] = {0}; // 3x3 网格,只能向右/下 05 f[0][0] = 1; 06 for (int i = 0; i < 3; i++) 07 for (int j = 0; j < 3; j++) { 08 if (i > 0) f[i][j] += f[i - 1][j]; 09 if (j > 0) f[i][j] += f[i][j - 1]; 10 } 11 cout << f[2][2]; // 从 (0,0) 到 (2,2) 的路径数 12 return 0; 13}
单选题:程序输出是?
考点:路径计数 DP 输出(I4)。
解析: 从 到 :。正确答案 A。
实现要点:计数 DP = 两个来源相加(上方 + 左方),。手算:逐格累加。
排除法:B(3)是 ;C(9)是格子数;D(20)无依据。
关联 · 路径计数的 DP(B4):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[5] = {3, 2, 5, 10, 7}; 05 int f[5]; 06 f[0] = a[0]; 07 f[1] = max(a[0], a[1]); 08 for (int i = 2; i < 5; i++) 09 f[i] = max(f[i - 1], f[i - 2] + a[i]); // 不选 / 选(跳过前一个) 10 cout << f[4]; 11 return 0; 12}
单选题:程序输出是?
考点:不相邻取数(I5)。
解析::3, 3, 8, 13, 15 → 输出 15(选 和为 15)。正确答案 A。
实现要点::第 5 项 。手算:逐项比较"不选/选"。
排除法:B(13)是少算的方案;C(17)连选了相邻;D(10)无依据。
关联 · 不相邻取数(B6):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 long long a = 1, b = 1; // 滚动变量 05 for (int i = 3; i <= 10; i++) { 06 long long c = a + b; 07 a = b; b = c; 08 } 09 cout << b; 10 return 0; 11}
单选题:程序输出是?
考点:斐波那契滚动 DP(I6)。
解析:滚动变量迭代 8 轮:。正确答案 A。
实现要点:滚动 = c = a + b; a = b; b = c——空间 。手算:。
排除法:B 是 ;C 是 ;D 是 。
关联 · 一维 DP 的滚动优化(B7):滚动代码。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int cost[6] = {0, 2, 3, 1, 5, 4}; // cost[i]:第 i 级台阶的费用 05 int f[6] = {0}; 06 f[1] = cost[1]; 07 f[2] = cost[2]; 08 for (int i = 3; i <= 5; i++) 09 f[i] = min(f[i - 1], f[i - 2]) + cost[i]; // 从上一级或上上级来 10 cout << f[5]; 11 return 0; 12}
单选题:程序输出是?
考点:台阶费用最小(I7)。
解析: → 输出 7。正确答案 A。
实现要点:最小费用 = min(f[i-1], f[i-2]) + cost[i]。手算:。
排除法:B(8)是 ;C(10)无依据;D(6)无依据。
关联 · 爬楼梯 DP 输出(I1):max 换 min 的镜像题。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[8] = {3, 1, 4, 1, 5, 9, 2, 6}; 05 int f[8], ans = 1; 06 for (int i = 0; i < 8; i++) { 07 f[i] = 1; // 初值:自己一个 08 for (int j = 0; j < i; j++) 09 if (a[j] < a[i]) f[i] = max(f[i], f[j] + 1); 10 ans = max(ans, f[i]); 11 } 12 cout << ans; // LIS 长度 13 return 0; 14}
单选题:程序输出是?
考点:LIS 的长度(J1)。
解析: 或 → 长度 4。正确答案 A。
实现要点:LIS 框架 = 双重循环 + a[j] < a[i] 条件 + f[i] = max(f[i], f[j]+1);答案取 max(f[*])。手算:逐 i 填 f。
排除法:B(3)漏算;C/D 无依据。
关联 · LIS 的转移方程(E2):框架代码。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[5] = {3, 1, 4, 1, 5}; 05 int f[5]; 06 for (int i = 0; i < 5; i++) { 07 f[i] = 1; 08 for (int j = 0; j < i; j++) 09 if (a[j] < a[i]) f[i] = max(f[i], f[j] + 1); 10 } 11 for (int i = 0; i < 5; i++) cout << f[i] << " "; // 输出每个 f[i] 12 return 0; 13}
单选题:程序输出是?
考点:LIS 的 f 数组(J2)。
解析:(对应 )。正确答案 A。
实现要点:输出 f 数组帮助理解转移过程——f[i] = 以 a[i] 结尾的 LIS 长度。手算:逐项验证。
排除法:B/C/D 与手算不符。
关联 · LIS 的长度(J1):同框架输出版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[5] = {1, 3, 3, 5, 2}; 05 int f[5], ans = 1; 06 for (int i = 0; i < 5; i++) { 07 f[i] = 1; 08 for (int j = 0; j < i; j++) 09 if (a[j] <= a[i]) f[i] = max(f[i], f[j] + 1); // 不下降:允许相等 10 ans = max(ans, f[i]); 11 } 12 cout << ans; // 最长不下降子序列长度 13 return 0; 14}
单选题:程序输出是?
考点:最长不下降子序列(J3)。
解析: → 长度 4(允许相等)。正确答案 A。
实现要点:条件 a[j] <= a[i](不下降)与严格上升只差等号。手算: 全保留。
排除法:B(3)用了严格条件;C/D 无依据。
关联 · LIS 的严格性(E1):等号之差。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[6] = {9, 4, 7, 2, 5, 1}; 05 int f[6], ans = 1; 06 for (int i = 0; i < 6; i++) { 07 f[i] = 1; 08 for (int j = 0; j < i; j++) 09 if (a[j] > a[i]) f[i] = max(f[i], f[j] + 1); // 严格下降 10 ans = max(ans, f[i]); 11 } 12 cout << ans; // 最长下降子序列长度 13 return 0; 14}
单选题:程序输出是?
考点:最长下降子序列(J4)。
解析: 或 → 长度 4。正确答案 A。
实现要点:条件 a[j] > a[i](严格下降)——与上升镜像。手算:逐项验证。
排除法:B(3)漏算;C(5)无依据;D(6)是元素数。
关联 · LIS 的长度(J1):方向变体。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[5] = {2, 1, 5, 3, 4}; 05 int f[5], pre[5], ans = 1, pos = 0; 06 for (int i = 0; i < 5; i++) { 07 f[i] = 1; pre[i] = -1; 08 for (int j = 0; j < i; j++) 09 if (a[j] < a[i] && f[j] + 1 > f[i]) { f[i] = f[j] + 1; pre[i] = j; } 10 if (f[i] > ans) { ans = f[i]; pos = i; } 11 } 12 vector<int> seq; // 沿 pre 回溯还原 LIS 13 for (int x = pos; x != -1; x = pre[x]) seq.push_back(a[x]); 14 for (int i = seq.size() - 1; i >= 0; i--) cout << seq[i] << " "; 15 return 0; 16}
单选题:程序输出是?
考点:LIS 的序列还原(J5)。
解析:转移顺序找到的 LIS 是 (,)→ 输出 2 3 4。正确答案 A。
实现要点:pre 记录转移来源 + 从答案位置倒推 + 反转输出。手算:沿 pre 链 。
排除法:B(1 3 4)是另一条等长 LIS(此题转移顺序未选它);C/D 不是 LIS。
关联 · LIS 的序列还原(E4):还原方法。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[5] = {5, 1, 2, 3, 4}; 05 int f[5], lis = 1; 06 for (int i = 0; i < 5; i++) { // LIS:不要求连续 07 f[i] = 1; 08 for (int j = 0; j < i; j++) 09 if (a[j] < a[i]) f[i] = max(f[i], f[j] + 1); 10 lis = max(lis, f[i]); 11 } 12 int cur = 0, best = 0; // 最大子段和:必须连续 13 for (int i = 0; i < 5; i++) { 14 cur += a[i]; 15 if (cur < 0) cur = 0; 16 best = max(best, cur); 17 } 18 cout << lis << " " << best; 19 return 0; 20}
单选题:程序输出是?
考点:LIS 与子段对比(J6)。
解析:LIS = 4(,不连续),最大子段和 = 15(全数组连续)→ 4 15。正确答案 A。
实现要点:两段代码并排——LIS 双重循环、子段 Kadane 单重。手算:分别算出再拼输出。
排除法:B(4 10)子段少算;C(5 15)LIS 多算;D(3 15)LIS 少算。
关联 · 子序列与子段(E5):对比的代码版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int w[5] = {0, 2, 3, 4, 5}; // 物品重量(1 下标) 05 int v[5] = {0, 3, 4, 5, 6}; // 物品价值 06 int C = 8, n = 4; 07 int f[10] = {0}; // 不超过容量,全 0 初始化 08 for (int i = 1; i <= n; i++) 09 for (int j = C; j >= w[i]; j--) // 容量倒序 10 f[j] = max(f[j], f[j - w[i]] + v[i]); 11 cout << f[C]; 12 return 0; 13}
单选题:程序输出是?
考点:01 背包最大价值(K1)。
解析:容量 8:选 价值 10(重量 8)最优。正确答案 A。
实现要点:滚动数组 01 背包 = 物品循环 + 容量倒序 + max(不选, 选)。手算:逐件更新 f 表。
排除法:B(9)是 超重的误解;C/D 无依据。
关联 · 容量循环必须倒序(C3):倒序的原因。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int w[2] = {0, 2}; // 只有一件物品:重 2 价值 3 05 int v[2] = {0, 3}; 06 int C = 6, f[10] = {0}; 07 for (int i = 1; i <= 1; i++) 08 for (int j = 0; j <= C; j++) // 错误:容量正序循环 09 if (j >= w[i]) f[j] = max(f[j], f[j - w[i]] + v[i]); 10 cout << f[C]; 11 return 0; 12}
单选题:程序输出是?(正确 01 背包结果应为 3)
考点:正序循环的错误输出(K2)。
解析:单件物品(重 2 值 3)正序循环:(同一件被选了 3 次)。正确答案 A。
实现要点:正序 = 本件物品可重复选(完全背包行为)——错误示范对照 C3。手算:。
排除法:B(3)是正确结果;C(6)是选了两次;D 无依据。
关联 · 背包正序的错误(H1):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int w[4] = {0, 2, 3, 5}; 05 int v[4] = {0, 3, 4, 7}; 06 int C = 8, n = 3; 07 int f[10]; 08 fill(f, f + 10, -1000000000); // 恰好装满:其余不可达 09 f[0] = 0; 10 for (int i = 1; i <= n; i++) 11 for (int j = C; j >= w[i]; j--) 12 f[j] = max(f[j], f[j - w[i]] + v[i]); 13 cout << f[C]; 14 return 0; 15}
单选题:程序输出是?
考点:恰好装满的价值(K3)。
解析:恰好 8 = → 11。正确答案 A。
实现要点:恰好装满 = -1e9 初始化 + f[0]=0——不可达容量保持极小值。手算:只有恰好装满的路径才有值。
排除法:B 是"不可达"的显示;C/D 是其他组合。
关联 · 恰好装满的初始化(C4):初始化代码。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int w[5] = {0, 1, 1, 2, 3}; // 四件物品的重量 05 int C = 4, n = 4; 06 int f[10] = {0}; 07 f[0] = 1; // 空集:1 种方案 08 for (int i = 1; i <= n; i++) 09 for (int j = C; j >= w[i]; j--) 10 f[j] += f[j - w[i]]; // 方案数用加法 11 cout << f[C]; 12 return 0; 13}
单选题:程序输出是?
考点:恰好装满的方案数(K4)。
解析::、 → 共 3 种。正确答案 A。
实现要点:方案数 = f[j] += f[j-w](加法)+ 倒序(01)+ f[0]=1。手算:逐件累加方案。
排除法:B(2)漏算;C(4)无依据;D(1)只算了一种。
关联 · 背包方案数的转移(C6):加法转移。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int w[4] = {0, 1, 3, 4}; 05 int v[4] = {0, 2, 5, 7}; 06 int C = 7, n = 3; 07 int f[10] = {0}; 08 for (int i = 1; i <= n; i++) 09 for (int j = C; j >= w[i]; j--) 10 f[j] = max(f[j], f[j - w[i]] + v[i]); 11 cout << f[C]; 12 return 0; 13}
单选题:程序输出是?
考点:滚动数组版(K5)。
解析:容量 7:选 → 12。正确答案 A。
实现要点:滚动数组 = 一维 f + 倒序——与二维版等价。手算:逐件倒序更新。
排除法:B(9)少选一件;C(14)超重;D(7)只选一件。
关联 · 二维表版(K6):两种实现的等价性。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int w[3] = {0, 2, 3}; 05 int v[3] = {0, 3, 4}; 06 int C = 5, n = 2; 07 int f[3][10] = {0}; // 二维表版 08 for (int i = 1; i <= n; i++) 09 for (int j = 0; j <= C; j++) { 10 f[i][j] = f[i - 1][j]; // 不选 11 if (j >= w[i]) f[i][j] = max(f[i][j], f[i - 1][j - w[i]] + v[i]); // 选 12 } 13 cout << f[n][C]; 14 return 0; 15}
单选题:程序输出是?
考点:二维表版(K6)。
解析:容量 5:选 → 7。正确答案 A。
实现要点:二维版 = f[i][j] = max(f[i-1][j], f[i-1][j-w]+v)——不选/选都显式,无需倒序。手算:逐行填表。
排除法:B(3)只选一件;C(4)无依据;D(10)超重。
关联 · 01 背包的状态定义(C1):二维状态。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int w[3] = {0, 2, 4}; 05 int v[3] = {0, 3, 5}; 06 int C = 5, n = 2; 07 int f[10]; 08 fill(f, f + 10, -1000000000); 09 f[0] = 0; 10 for (int i = 1; i <= n; i++) 11 for (int j = C; j >= w[i]; j--) 12 f[j] = max(f[j], f[j - w[i]] + v[i]); 13 cout << (f[C] < 0 ? -1 : f[C]); // 恰好装满不可达 → -1 14 return 0; 15}
单选题:程序输出是?
考点:不可达的判断(K7)。
解析:恰好 5 无组合()→ f[5] 保持 → 输出 -1。正确答案 A。
实现要点:恰好装满 + 判断 f[C] < 0 输出 -1——先查可达性再取值。手算:验证无组合可达。
排除法:B(0)是错误初始化;C(8)是超重组合;D(3)无依据。
关联 · 恰好装满的初始化(C4):不可达的处理。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[3][3] = {{1, 3, 1}, {1, 5, 1}, {4, 2, 1}}; // 3x3 矩阵 05 int f[3][3] = {0}; 06 f[0][0] = a[0][0]; 07 for (int i = 0; i < 3; i++) 08 for (int j = 0; j < 3; j++) { 09 if (i == 0 && j == 0) continue; 10 int best = -1e9; 11 if (i > 0) best = max(best, f[i - 1][j]); 12 if (j > 0) best = max(best, f[i][j - 1]); 13 f[i][j] = best + a[i][j]; 14 } 15 cout << f[2][2]; // 最大路径和 16 return 0; 17}
单选题:程序输出是?
考点:矩阵最大路径和输出(L1)。
解析::。正确答案 A。
实现要点:二维 DP = 双循环 + 上/左取 max + 边界判断。手算:逐格填表 。
排除法:B(11)某格少算;C/D 无依据。
关联 · 矩阵最大路径和(D2):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[3][3] = {{1, 3, 1}, {1, 5, 1}, {4, 2, 1}}; 05 int f[3][3] = {0}; 06 f[0][0] = a[0][0]; 07 for (int j = 1; j < 3; j++) f[0][j] = f[0][j - 1] + a[0][j]; // 第一行只能从左来 08 for (int j = 0; j < 3; j++) cout << f[0][j] << " "; 09 return 0; 10}
单选题:程序输出是?
考点:边界行输出(L2)。
解析:第一行只能从左来: → 1 4 5。正确答案 A。
实现要点:边界行单独递推:f[0][j] = f[0][j-1] + a[0][j]。手算:。
排除法:B 是原数据;C 某格错;D 无依据。
关联 · 边界行与列(D4):边界处理的代码。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int g[3][3] = {{0, 0, 0}, {0, 1, 0}, {0, 0, 0}}; // (1,1) 是障碍 05 int f[3][3] = {0}; 06 f[0][0] = 1; 07 for (int i = 0; i < 3; i++) 08 for (int j = 0; j < 3; j++) { 09 if (g[i][j] == 1) { f[i][j] = 0; continue; } // 障碍格不可达 10 if (i > 0) f[i][j] += f[i - 1][j]; 11 if (j > 0) f[i][j] += f[i][j - 1]; 12 } 13 cout << f[2][2]; // 绕过障碍的路径数 14 return 0; 15}
单选题:程序输出是?
考点:障碍物路径数(L3)。
解析: 是障碍:。正确答案 A。
实现要点:计数 DP + 障碍格置 0 跳过。手算:绕行两条路(上-右-右-下 与 右-下-右-下 变形)。
排除法:B(1)漏一条;C/D 无依据。
关联 · 障碍物的处理(D5):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[2][2] = {{2, 3}, {5, 1}}; 05 int f[2] = {0}; // 滚动数组:只保留一行 06 f[0] = a[0][0]; 07 f[1] = f[0] + a[0][1]; // 第 0 行 08 for (int j = 0; j < 2; j++) { // 逐行滚动 09 if (j == 0) f[0] = f[0] + a[1][0]; 10 else f[j] = max(f[j], f[j - 1]) + a[1][j]; 11 } 12 cout << f[1]; // 最大路径和 13 return 0; 14}
单选题:程序输出是?
考点:逐行滚动版(L4)。
解析:滚动数组: → 输出 8( 或 路径:)。正确答案 A。
实现要点:逐行滚动 = 每行只用上一行的 f;f[j] = max(f[j], f[j-1]) + a[i][j](f[j] 是上一行值、f[j-1] 是本行已更新值)。手算:。
排除法:B(5)只算一行;C(6)走 2→3→1;D 无依据。
关联 · 二维 DP 的滚动优化(D7):滚动实现。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[3][3] = {{1, 3, 1}, {1, 5, 1}, {4, 2, 1}}; 05 int f[3][3] = {0}; 06 f[0][0] = a[0][0]; 07 for (int i = 0; i < 3; i++) 08 for (int j = 0; j < 3; j++) { 09 if (i == 0 && j == 0) continue; 10 int best = -1e9; 11 if (i > 0) best = max(best, f[i - 1][j]); 12 if (j > 0) best = max(best, f[i][j - 1]); 13 f[i][j] = best + a[i][j]; 14 } 15 for (int i = 0; i < 3; i++) { // 打印整张 DP 表 16 for (int j = 0; j < 3; j++) cout << f[i][j] << " "; 17 cout << endl; 18 } 19 return 0; 20}
单选题:程序输出是?
考点:打印二维 DP 表(L5)。
解析: 表:1 4 5、2 9 10、6 11 12。正确答案 A。
实现要点:打印整张表用于调试(G6)。手算:逐格验证。
排除法:B 是原数据;C/D 某格错。
关联 · 打印 DP 表调试(G6):调试方法。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[3][3] = {{1, 3, 1}, {1, 5, 1}, {4, 2, 1}}; 05 int f[3][3] = {0}; 06 f[0][0] = a[0][0]; 07 for (int i = 0; i < 3; i++) 08 for (int j = 0; j < 3; j++) { 09 if (i == 0 && j == 0) continue; 10 int best = -1e9; 11 if (i > 0) best = max(best, ______); // 上方来源 12 if (j > 0) best = max(best, f[i][j - 1]); 13 f[i][j] = best + a[i][j]; 14 } 15 cout << f[2][2]; 16 return 0; 17}
单选题:横线处应填入?
考点:补全二维转移(L6)。
解析:上方来源 f[i - 1][j]。运行:。正确答案 A。
实现要点:两个来源(上、左)都要写、都要带边界判断。手算:。
排除法:B 重复左方;C 越界下方;D 斜对角(此题不可斜走)。
关联 · 二维转移的来源(D3):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[3][3] = {{3, 0, 0}, {1, 5, 0}, {8, 6, 7}}; 05 int f[3][3] = {0}; 06 f[0][0] = a[0][0]; 07 for (int i = 1; i < 3; i++) 08 for (int j = 0; j <= i; j++) { 09 f[i][j] = a[i][j]; 10 if (j > 0) f[i][j] = max(f[i][j], f[i - 1][j - 1] + a[i][j]); 11 if (j < i) f[i][j] = max(f[i][j], f[i - 1][j] + a[i][j]); 12 } 13 cout << max({f[2][0], f[2][1], f[2][2]}); 14 return 0; 15}
单选题:程序输出是?
考点:自顶向下输出(M1)。
解析:。正确答案 A。
实现要点:自顶向下 = 从根往下填表,最后一行取 max。手算:。
排除法:B 是 ;C 是 ;D 是 。
关联 · 数字三角形的状态(B3):转移方向。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[4][4] = {{5, 0, 0, 0}, {2, 8, 0, 0}, {9, 4, 7, 0}, {3, 6, 8, 2}}; 05 int f[4][4] = {0}; 06 for (int j = 0; j < 4; j++) f[3][j] = a[3][j]; // 最后一行 07 for (int i = 2; i >= 0; i--) // 自底向上 08 for (int j = 0; j <= i; j++) 09 f[i][j] = a[i][j] + max(f[i + 1][j], f[i + 1][j + 1]); 10 cout << f[0][0]; // 顶点最大值 11 return 0; 12}
单选题:程序输出是?
考点:自底向上输出(M2)。
解析:底部 逐层向上:。正确答案 A。
实现要点:自底向上 = 最后一行初始化 + 从下往上取 两个下方来源。手算:第 3 层 ,第 2 层 ,顶点 。
排除法:B/C/D 与手算不符。
关联 · 自顶向下输出(M1):两种方向等价。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[3][3] = {{3, 0, 0}, {1, 5, 0}, {8, 6, 7}}; 05 int f[3][3] = {0}, from[3][3]; // from 记录上一行来源 06 f[0][0] = a[0][0]; 07 for (int i = 1; i < 3; i++) 08 for (int j = 0; j <= i; j++) { 09 int best = -1, src = -1; 10 if (j > 0 && f[i - 1][j - 1] > best) { best = f[i - 1][j - 1]; src = j - 1; } 11 if (j < i && f[i - 1][j] > best) { best = f[i - 1][j]; src = j; } 12 f[i][j] = best + a[i][j]; 13 from[i][j] = src; 14 } 15 int p = (f[2][0] >= f[2][1] ? (f[2][0] >= f[2][2] ? 0 : 2) : (f[2][1] >= f[2][2] ? 1 : 2)); 16 vector<int> path; 17 for (int i = 2; i >= 0; i--) { path.push_back(a[i][p]); p = from[i][p]; } 18 for (int i = path.size() - 1; i >= 0; i--) cout << path[i] << " "; 19 return 0; 20}
单选题:程序输出是?
考点:路径记录输出(M3)。
解析:最优路径 → 3 5 7。正确答案 A。
实现要点:from[i][j] 记录来源列 + 从最优终点倒推路径。手算: 最大,来源列依次 。
排除法:B 是 路径;C 是 ;D 无依据。
关联 · 路径记录输出(第 14 章 J5):倒推思想的迁移。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[3][3] = {{3, 0, 0}, {1, 5, 0}, {8, 6, 7}}; 05 int f[3][3] = {0}; 06 f[0][0] = a[0][0]; 07 for (int i = 1; i < 3; i++) 08 for (int j = 0; j <= i; j++) { 09 f[i][j] = INT_MAX; 10 if (j > 0) f[i][j] = min(f[i][j], f[i - 1][j - 1] + a[i][j]); 11 if (j < i) f[i][j] = min(f[i][j], f[i - 1][j] + a[i][j]); 12 } 13 cout << min({f[2][0], f[2][1], f[2][2]}); // 最小路径和 14 return 0; 15}
单选题:程序输出是?
考点:最小路径和(M4)。
解析:最小路径 。正确答案 A。
实现要点:max 换 min 即最小路径——注意初值用 INT_MAX。手算:,取 10。
排除法:B 是 ;C 是最大路径;D 无依据。
关联 · 自顶向下输出(M1):镜像题。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[3][3] = {{3, 0, 0}, {1, 5, 0}, {8, 6, 7}}; 05 int f[3][3] = {0}; 06 f[0][0] = a[0][0]; 07 for (int i = 1; i < 3; i++) 08 for (int j = 0; j <= i; j++) { 09 f[i][j] = a[i][j]; 10 if (j > 0) f[i][j] = max(f[i][j], f[i - 1][j - 1] + a[i][j]); 11 if (j < i) f[i][j] = max(f[i][j], f[i - 1][j] + a[i][j]); 12 } 13 for (int j = 0; j < 3; j++) cout << f[2][j] << " "; // 打印最后一行 14 return 0; 15}
单选题:程序输出是?
考点:打印 DP 表(M5)。
解析:最后一行 12 14 15。正确答案 A。
实现要点:打印 DP 表 = 输出 f 数组某行/整表——调试利器(G6)。手算:逐格验证。
排除法:B/C 某一格错;D 是原数据。
关联 · 打印 DP 表调试(G6):调试方法。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[3][3] = {{3, 0, 0}, {1, 5, 0}, {8, 6, 7}}; 05 int f[3][3] = {0}; 06 f[0][0] = a[0][0]; 07 for (int i = 1; i < 3; i++) 08 for (int j = 0; j <= i; j++) 09 f[i][j] = ______ + a[i][j]; // 取上一行两个来源(注意越界)的最大值 10 cout << max({f[2][0], f[2][1], f[2][2]}); 11 return 0; 12}
单选题:横线处应填入?
考点:补全转移方程(M6)。
解析:两个来源都要带边界判断:max((j>0 ? f[i-1][j-1] : 0), (j<i ? f[i-1][j] : 0))。正确答案 A。
实现要点:三角形 DP 的边界: 无左上、 无正上——越界处用 0(或跳过)。手算: 只有正上来源。
排除法:B 会越界读 f[i-1][-1];C 是取 min;D 漏了正上来源。
关联 · 下标边界的处理(G5):边界判断。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int f[15]; 05 f[1] = 1; f[2] = 2; 06 for (int i = 3; i <= 10; i++) 07 f[i] = ______; // 爬楼梯转移 08 cout << f[10]; 09 return 0; 10}
单选题:横线处应填入?
考点:补全爬楼梯转移(N1)。
解析:f[i-1] + f[i-2]。运行:。正确答案 A。
实现要点:转移 = 前两项之和。手算:代入验证。
排除法:B 乘法;C 加 i;D 等比——都不符合"两步之和"。
关联 · 爬楼梯 DP 输出(I1):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[8] = {3, 1, 4, 1, 5, 9, 2, 6}; 05 int f[8], ans = 1; 06 for (int i = 0; i < 8; i++) { 07 f[i] = 1; 08 for (int j = 0; j < i; j++) 09 if (______) f[i] = max(f[i], f[j] + 1); // LIS 转移条件 10 ans = max(ans, f[i]); 11 } 12 cout << ans; 13 return 0; 14}
单选题:横线处应填入?
考点:补全 LIS 转移(N2)。
解析:条件 a[j] < a[i](严格上升)。运行:LIS = 4。正确答案 A。
实现要点:转移条件 = 前驱值小于当前值。手算:。
排除法:B 是下降;C 是相等;D 无条件。
关联 · LIS 的长度(J1):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int w[5] = {0, 2, 3, 4, 5}; 05 int v[5] = {0, 3, 4, 5, 6}; 06 int C = 8, n = 4, f[10] = {0}; 07 for (int i = 1; i <= n; i++) 08 for (int j = ______; j >= w[i]; j--) // 01 背包容量倒序 09 f[j] = max(f[j], f[j - w[i]] + v[i]); 10 cout << f[C]; 11 return 0; 12}
单选题:横线处应填入?
考点:补全背包倒序循环(N3)。
解析:容量从 C 倒到 w[i]。运行:。正确答案 A。
实现要点:倒序起点 = 最大容量 C,终点 = w[i](更小容量放不下)。手算:逐件更新。
排除法:B 只算一个容量;C 是物品数;D 漏了容量范围。
关联 · 容量循环必须倒序(C3):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[3][3] = {{3, 0, 0}, {1, 5, 0}, {8, 6, 7}}; 05 int f[3][3] = {0}; 06 f[0][0] = a[0][0]; 07 for (int i = 1; i < 3; i++) 08 for (int j = 0; j <= i; j++) { 09 f[i][j] = a[i][j]; 10 if (j > 0) f[i][j] = max(f[i][j], ______); // 左上来源 11 if (j < i) f[i][j] = max(f[i][j], f[i - 1][j] + a[i][j]); // 正上来源 12 } 13 cout << max({f[2][0], f[2][1], f[2][2]}); 14 return 0; 15}
单选题:横线处应填入?
考点:补全数字三角形转移(N4)。
解析:左上来源 f[i-1][j-1] + a[i][j]。运行:最大路径 15。正确答案 A。
实现要点:两个来源(左上、正上)都要写。手算:。
排除法:B 同行左;C 重复正上;D 自引用。
关联 · 数字三角形的状态(B3):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[3][3] = {{1, 3, 1}, {1, 5, 1}, {4, 2, 1}}; 05 int f[3][3] = {0}; 06 f[0][0] = a[0][0]; 07 for (int i = 0; i < 3; i++) 08 for (int j = 0; j < 3; j++) { 09 if (i == 0 && j == 0) continue; 10 int best = -1e9; 11 if (i > 0) best = max(best, f[i - 1][j]); 12 if (j > 0) best = max(best, ______); // 左方来源 13 f[i][j] = best + a[i][j]; 14 } 15 cout << f[2][2]; 16 return 0; 17}
单选题:横线处应填入?
考点:补全二维转移(N5)。
解析:左方来源 f[i][j - 1]。运行:。正确答案 A。
实现要点:与 L6 互为镜像:L6 补上方、本题补左方。手算:,。
排除法:B 是上方来源(重复);C 越界右方;D 斜对角。
关联 · 二维转移的来源(D3):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int w[4] = {0, 2, 3, 5}; 05 int v[4] = {0, 3, 4, 7}; 06 int C = 8, n = 3; 07 int f[10]; 08 ______; // 恰好装满:只有 f[0] 合法 09 f[0] = 0; 10 for (int i = 1; i <= n; i++) 11 for (int j = C; j >= w[i]; j--) 12 f[j] = max(f[j], f[j - w[i]] + v[i]); 13 cout << f[C]; 14 return 0; 15}
单选题:横线处应填入?
考点:补全恰好装满初始化(N6)。
解析:fill(f, f+10, -1000000000)——只有 f[0] 合法。运行:。正确答案 A。
实现要点:恰好装满的初始化 = 极小值 + f[0]=0。手算:恰好 8 = 。
排除法:B/C 全 0 会"没装满也合法";D 排序无关。
关联 · 恰好装满的初始化(C4):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int f[3][3] = {0}; 05 f[0][0] = 1; 06 for (int i = 0; i < 3; i++) 07 for (int j = 0; j < 3; j++) { 08 if (i > 0) f[i][j] += ______; // 从上方来 09 if (j > 0) f[i][j] += f[i][j - 1]; // 从左方来 10 } 11 cout << f[2][2]; 12 return 0; 13}
单选题:横线处应填入?
考点:补全路径计数转移(N7)。
解析:上方来源 f[i-1][j]。运行:。正确答案 A。
实现要点:计数 DP 两个来源相加:上 + 左。手算:。
排除法:B 重复左方;C 越界下方;D 是斜对角(此题不可斜走)。
关联 · 路径计数的 DP(B4):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int w[4] = {0, 1, 2, 3}; // 重量 05 int v[4] = {0, 2, 3, 5}; // 价值 06 int C = 3, n = 3; 07 int f[10] = {0}, g[10] = {0}; // f:价值,g:方案数 08 g[0] = 1; 09 for (int i = 1; i <= n; i++) 10 for (int j = C; j >= w[i]; j--) { 11 if (f[j - w[i]] + v[i] > f[j]) { f[j] = f[j - w[i]] + v[i]; g[j] = g[j - w[i]]; } 12 else if (f[j - w[i]] + v[i] == f[j]) g[j] += g[j - w[i]]; 13 } 14 cout << g[C]; // 最优价值对应的方案数 15 return 0; 16}
单选题:程序输出是?
考点:背包与方案数综合(O1)。
解析:容量 3 最优价值 5(选物品 3 或物品 1+2),两种方案 → 输出 2。正确答案 A。
实现要点:价值 DP 与方案数 DP 并行:更优则覆盖方案、相等则累加。手算:逐件更新 f 与 g。
排除法:B(1)漏算并列方案;C/D 无依据。
关联 · 背包方案数的转移(C6):综合应用。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[3][3] = {{1, 0, 0}, {-2, 3, 0}, {4, -5, 6}}; 05 int f[3][3]; 06 for (int i = 0; i < 3; i++) 07 for (int j = 0; j < 3; j++) f[i][j] = INT_MIN; // 含负数,初值要极小 08 f[0][0] = a[0][0]; 09 for (int i = 1; i < 3; i++) 10 for (int j = 0; j <= i; j++) { 11 int best = INT_MIN; 12 if (j > 0) best = max(best, f[i - 1][j - 1]); 13 if (j < i) best = max(best, f[i - 1][j]); 14 f[i][j] = best + a[i][j]; 15 } 16 cout << max({f[2][0], f[2][1], f[2][2]}); 17 return 0; 18}
单选题:程序输出是?
考点:数字三角形含负数(O2)。
解析:最优路径 。正确答案 A。
实现要点:含负数时初值必须极小(INT_MIN)——否则负数会被"0"挡住。手算:。
排除法:B(7)漏算;C(3)无依据;D(12)超范围。
关联 · 下标边界的处理(G5):负数边界的处理。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[4] = {1, 3, 2, 4}; 05 int f[4], g[4], ans = 1, ways = 0; 06 for (int i = 0; i < 4; i++) { 07 f[i] = 1; g[i] = 1; 08 for (int j = 0; j < i; j++) 09 if (a[j] < a[i]) { 10 if (f[j] + 1 > f[i]) { f[i] = f[j] + 1; g[i] = g[j]; } 11 else if (f[j] + 1 == f[i]) g[i] += g[j]; 12 } 13 if (f[i] > ans) { ans = f[i]; ways = g[i]; } 14 else if (f[i] == ans) ways += g[i]; 15 } 16 cout << ans << " " << ways; // 最长长度与方案数 17 return 0; 18}
单选题:程序输出是?
考点:LIS 与方案计数(O3)。
解析:LIS 长度 3( 与 两条)→ 3 2。正确答案 A。
实现要点:方案数 DP 与价值 DP 并行:更优覆盖、相等累加(同 O1 思想)。手算:、。
排除法:B(3 1)漏方案;C(4 1)长度错;D 无依据。
关联 · LIS 的多条方案(E6):计数实现。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[2][3] = {{1, 2, 3}, {4, 5, 6}}; // 2x3 矩阵 05 int f[2][3] = {0}; 06 f[0][0] = a[0][0]; 07 for (int i = 0; i < 2; i++) 08 for (int j = 0; j < 3; j++) { 09 if (i == 0 && j == 0) continue; 10 int best = -1e9; 11 if (i > 0) best = max(best, f[i - 1][j]); 12 if (j > 0) best = max(best, f[i][j - 1]); 13 f[i][j] = best + a[i][j]; 14 } 15 cout << f[1][2]; // 最大路径和 16 return 0; 17}
单选题:程序输出是?
考点:矩阵最大路径和(O4)。
解析::。正确答案 A。
实现要点:同 L1 框架换数据。手算:(走下方再右), 更小。
排除法:B(12)走的是上边路径;C/D 无依据。
关联 · 矩阵最大路径和输出(L1):同框架不同数据。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int w[4] = {0, 1, 2, 3}; 05 int v[4] = {0, 2, 3, 5}; 06 int C = 4, n = 3; 07 int f[10]; 08 fill(f, f + 10, -1000000000); 09 f[0] = 0; 10 for (int i = 1; i <= n; i++) 11 for (int j = C; j >= w[i]; j--) 12 f[j] = max(f[j], f[j - w[i]] + v[i]); 13 cout << f[C]; // 恰好装满 C 的最大价值 14 return 0; 15}
单选题:程序输出是?
考点:恰好装满综合(O5)。
解析:恰好 4 = → 7。正确答案 A。
实现要点:恰好装满框架 + 综合数据。手算:。
排除法:B(5)是只选物品 3(装不满 4);C 无依据;D 是不可达。
关联 · 恰好装满的价值(K3):同框架。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int w[3] = {0, 2, 3}; 05 int v[3] = {0, 3, 4}; 06 int C = 8, f[10] = {0}; 07 for (int i = 1; i <= 2; i++) 08 for (int j = 0; j <= C; j++) // 错误:容量正序 09 if (j >= w[i]) f[j] = max(f[j], f[j - w[i]] + v[i]); 10 cout << f[C]; // 正确 01 背包应为 7 11 return 0; 12}
单选题:程序输出是?
考点:正序循环的错误输出(P1)。
解析:两件物品正序:(物品可被重复选)。正确答案 A。
实现要点:错误示范对照——正序 = 完全背包行为。手算: 被逐容量推高。
排除法:B(7)是正确结果;C/D 无依据。
关联 · 背包正序的错误(H1):易错代码实证。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int w[3] = {0, 2, 4}; 05 int v[3] = {0, 3, 5}; 06 int C = 5, f[10] = {0}; // 错误:恰好装满却全 0 初始化 07 for (int i = 1; i <= 2; i++) 08 for (int j = C; j >= w[i]; j--) 09 f[j] = max(f[j], f[j - w[i]] + v[i]); 10 cout << f[C]; // 恰好 5 其实不可达(正确应输出 -1) 11 return 0; 12}
单选题:程序输出是?
考点:初始化错误的输出(P2)。
解析:恰好装满却全 0 初始化 → "没装满"也算合法:(只装物品 2,重 4 值 5)。正确答案 A。
实现要点:错误初始化 = 把"不超过"语义混进"恰好"题。手算:。
排除法:B(-1)是正确写法的输出;C/D 无依据。
关联 · 初始化错误(H2):代码实证。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int w[2] = {0, 2}; 05 int v[2] = {0, 3}; 06 int C = 4, f[10] = {0}; 07 for (int i = 1; i <= 1; i++) 08 for (int j = w[i]; j <= C; j++) 09 f[j] = f[j - w[i]] + v[i]; // 错误:漏了"不选"(f[j] 被覆盖) 10 cout << f[C]; // 正确结果应为 3 11 return 0; 12}
单选题:程序输出是?
考点:覆盖式转移的错误输出(P3)。
解析:漏"不选"(直接覆盖): → 输出 6(正确 3)。正确答案 A。
实现要点:01 背包必须 max(旧值, 新值)——漏掉旧值 = 同一件物品被多次累加。手算:。
排除法:B(3)是正确结果;C/D 无依据。
关联 · 转移漏选(H3):代码实证。
单选题:01 背包滚动数组版把内层写成 for (int j = 0; j <= C; j++) f[j] = max(f[j], f[j - w] + v);(没有 j >= w 判断),会发生什么?
考点:容量下标越界(P4)。
解析:j < w 时 f[j-w] 下标为负 → 越界,行为未定义。正确答案 A。
排除法:B/C 是幻想;D 能编译。
关联 · 下标边界的处理(G5):边界判断的必要性。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[4] = {1, 2, 1, 3}; 05 int f[4]; 06 f[0] = 1; 07 for (int i = 1; i < 4; i++) 08 f[i] = (a[i] > a[i - 1]) ? f[i - 1] + 1 : 1; // 错误:只统计"连续"上升段 09 cout << f[3]; // 正确 LIS(不要求连续)应为 3 10 return 0; 11}
单选题:程序输出是?
考点:连续与不连续的混淆(P5)。
解析:只统计连续上升段: → 输出 2(正确 LIS 应为 3:)。正确答案 A。
实现要点:LIS 的正确转移要枚举所有前驱 ,而不是只看 。手算: 跨过中间的 1。
排除法:B(3)是正确 LIS;C/D 无依据。
关联 · 子序列与子段(E5):概念的代码混淆。
判断题:以下结论全部正确——"滚动数组 01 背包容量必须倒序;LIS 的答案是 max(f[1..n]);二维 DP 边界行列要特判;恰好装满背包初始化只有 f[0] = 0 合法"。
考点:DP 代码综合判断(P6)。
解析:四句全部正确:背包倒序、LIS 取 max、二维 DP 边界特判、恰好装满 f[0]=0 唯一合法。✅ 正确
排除法:无(判断题)。混淆点:这是代码组的结论汇总,逐条对照各组题目。
关联 · DP 综合判断(H5):概念组与代码组的双总结。