林老师 · 客观题题库 · CSP-J 学习卷 L26 · 搜索

CSP-J 学习卷 L26 · 搜索

入门级算法 · 搜索思想与搜索树 / DFS 回溯排列·子集 / BFS 队列·最短路 / Flood Fill 连通块 / 剪枝·记忆化 / 真题形态
真题
复刻
试卷编号LEARN-J-26
题目总数102 题 · 143 分
试卷类型客观题
考生须知:
① 本卷共 7 大部分,合计 102 题 · 143 分,全部为客观题;
② 试卷右上角设有 「提交答卷」 与 「重置考试」 按钮,提交后系统自动判分并显示答题正确情况,请确认全部作答后再行提交;
③ 试卷不显示答案,提交后方可查看每题作答与正确答案的对照;
④ 答卷进度会保留在本地缓存中,刷新或再次打开仍可继续作答;
⑤ 本卷仅供学生练习使用;请勿用于其他用途;题面有问题请联系:i64coder@163.com。

判 分 报 告

0 / 143 分
0
答 对 · 得 0 分
0
答 错 · 失 0 分
当前筛选下没有题目
壹

认识搜索:状态、搜索树与完备枚举

12 计分点 · 每点 1 分
第 1 题 单选 未作答

下面哪个说法最符合算法竞赛里「搜索」这个词的含义?

(1 分)
原创教学题 | 考点:概念:搜索的基本含义辨析
第 2 题 单选 未作答

不加错误剪枝的暴力搜索「保证不遗漏正确答案」的根本原因是什么?

(1 分)
原创教学题 | 考点:概念:完备性(为什么暴力搜索不漏解)
第 3 题 单选 未作答

有人把「搜索」理解成「随机挑几个方案试一试」。为什么搜索必须是「有组织地枚举」,而不是随机尝试?

01int tries = 0;
02while (tries < 100) {
03    int p = rand() % N;
04    if (valid(p)) { cout << p << endl; return 0; }
05    tries++;
06}

(1 分)
原创教学题 | 考点:为什么:搜索是「有组织」的枚举而不是随机试
第 4 题 单选 未作答

一棵「每层做一次二选一决策」的搜索树,从根出发做 3 次决策,一共会得到多少种不同的结果(叶子)?

(1 分)
原创教学题 | 考点:追踪:二选一决策 3 次的叶子数
第 5 题 单选 未作答

枚举时每层可选项数递减:全排列问题(n=5n=5,5 个不同数字排成一列)的叶子数是?子集问题(n=5n=5,每个元素选或不选)的叶子数是?

(1 分)
原创教学题 | 考点:追踪:全排列 n=5 与子集 n=5 的叶子数
第 6 题 单选 未作答

一个搜索树每层有 3 个分支,深度为 4(从根到叶做 4 次决策),叶子数是多少?

(1 分)
原创教学题 | 考点:追踪:三叉搜索树深度 4 的叶子数
第 7 题 单选 未作答

下面哪个问题需要把状态「抽象成隐式状态空间」来做搜索?

(1 分)
原创教学题 | 考点:概念:显式图 vs 隐式状态空间
第 8 题 单选 未作答

倒水问题:一个 3 升壶和一个 5 升壶,状态就是当前水量组合 (x,y)(x, y)——xx 是 3 升壶里的水量(取 0~3),yy 是 5 升壶里的水量(取 0~5)。不管按什么顺序倒,只要两壶水量一样,接下来能做的倒法就完全一样。BFS 把每个到过的 (x,y)(x, y) 编码进标记数组,整个搜索长这样:

01#include <bits/stdc++.h>
02using namespace std;
03
04int key(int x, int y) { return x * 6 + y; }
05bool vis[24];
06queue<pair<int, int>> q;
07
08void push(int x, int y) {
09    if (!vis[key(x, y)]) {
10        vis[key(x, y)] = true;
11        q.push({x, y});
12    }
13}
14
15int main() {
16    push(0, 0);
17    while (!q.empty()) {
18        pair<int, int> u = q.front();
19        q.pop();
20        int x = u.first, y = u.second;
21        push(3, y); push(x, 5);
22        push(0, y); push(x, 0);
23        push(max(0, x + y - 5), min(5, x + y));
24        push(min(3, x + y), max(0, x + y - 3));
25    }
26}

为什么搜索要盯住「状态」把它抽象成节点来判重(push 里用 vis[key] 拦住重复),而不是直接盯着「倒水操作序列」往下搜?

(1 分)
原创教学题 | 考点:为什么:状态抽象成节点的意义(倒水问题情境)
第 9 题 单选 未作答

搜索树规模是指数级的,为什么竞赛题还是大量使用搜索?

(1 分)
原创教学题 | 考点:为什么:指数搜索比赛里还要用
第 10 题 单选 未作答

关于搜索树,下面哪个说法正确?

(1 分)
原创教学题 | 考点:概念:搜索树节点与路径含义
第 11 题 单选 未作答

已知状态数有 101210^{12} 个且没有剪枝手段,直接用搜索求答案,后果是什么?

(1 分)
原创教学题 | 考点:为什么:什么时候搜索不可行
第 12 题 单选 未作答

一个搜索树每层 2 个分支、深度 10 时叶子数是 210=10242^{10} = 1024。若每层 3 个分支、深度 6,叶子数是?

(1 分)
原创教学题 | 考点:追踪:3 叉深度 6 的叶子数
贰

DFS 与回溯:排列与子集

29 计分点 · 每点 1 分
第 13 题 单选 未作答

DFS(深度优先搜索)借助什么结构保证「先深入、后回退」?

(1 分)
原创教学题 | 考点:概念:DFS 与栈的关系
第 14 题 单选 未作答

全排列问题:把 1∼n1 \sim n 的每个数选恰好一次,按字典序输出全部排列。把下面代码里的恢复行 used[i] = false; 删掉,对 n=2n = 2 运行,输出什么?

01int a[10]; bool used[10]; int n;
02void dfs(int k) {
03    if (k == n) {
04        for (int i = 0; i < n; i++) cout << a[i];
05        cout << endl;
06        return;
07    }
08    for (int i = 1; i <= n; i++) {
09        if (used[i]) continue;
10        a[k] = i;
11        used[i] = true;
12        dfs(k + 1);
13    }
14}

(1 分)
原创教学题 | 考点:追踪:删掉恢复行 n=2 输出什么
第 15 题 单选 未作答

全排列代码里的 used[i] = false;(恢复现场)为什么不能删?

01int a[10]; bool used[10]; int n;
02void dfs(int k) {
03    if (k == n) {
04        for (int i = 0; i < n; i++) cout << a[i];
05        cout << endl;
06        return;
07    }
08    for (int i = 1; i <= n; i++) {
09        if (used[i]) continue;
10        a[k] = i;
11        used[i] = true;
12        dfs(k + 1);
13        used[i] = false;
14    }
15}

(1 分)
原创教学题 | 考点:为什么:恢复现场为什么不能删
第 16 题 单选 未作答

对 n=3n = 3 运行全排列程序,按字典序输出的第 4 个排列是什么?

01int a[10]; bool used[10]; int n;
02void dfs(int k) {
03    if (k == n) {
04        for (int i = 0; i < n; i++) cout << a[i];
05        cout << endl;
06        return;
07    }
08    for (int i = 1; i <= n; i++) {
09        if (used[i]) continue;
10        a[k] = i;
11        used[i] = true;
12        dfs(k + 1);
13        used[i] = false;
14    }
15}

(1 分)
原创教学题 | 考点:追踪:n=3 字典序第 4 个排列
第 17 题 单选 未作答

n=4n = 4 时全排列程序一共输出多少行?

01int a[10]; bool used[10]; int n;
02void dfs(int k) {
03    if (k == n) {
04        for (int i = 0; i < n; i++) cout << a[i];
05        cout << endl;
06        return;
07    }
08    for (int i = 1; i <= n; i++) {
09        if (used[i]) continue;
10        a[k] = i;
11        used[i] = true;
12        dfs(k + 1);
13        used[i] = false;
14    }
15}

(1 分)
原创教学题 | 考点:追踪:n=4 全排列行数
第 18 题 单选 未作答

补全全排列的两处空缺:进入分支前要 ____ 让下一层不再选它,递归返回后要 ____ 让同层其他分支还能用它。

01int a[10]; bool used[10]; int n;
02void dfs(int k) {
03    if (k == n) { for (int i = 0; i < n; i++) cout << a[i]; cout << endl; return; }
04    for (int i = 1; i <= n; i++) {
05        if (used[i]) continue;
06        a[k] = i;
07        used[i] = ____;
08        dfs(k + 1);
09        used[i] = ____;
10    }
11}

(1 分)
原创教学题 | 考点:挖空:补全全排列模板
第 19 题 单选 未作答

为什么 used[i] = true; 必须放在 dfs(k + 1); 调用之前?

01for (int i = 1; i <= n; i++) {
02    if (used[i]) continue;
03    a[k] = i;
04    used[i] = true;
05    dfs(k + 1);
06    used[i] = false;
07}

(1 分)
原创教学题 | 考点:为什么:标记必须在递归前
第 20 题 单选 未作答

全排列循环里误加了一行 return;,对 n=3n = 3 运行会怎样?

01int a[10]; bool used[10]; int n;
02void dfs(int k) {
03    if (k == n) { for (int i = 0; i < n; i++) cout << a[i]; cout << endl; return; }
04    for (int i = 1; i <= n; i++) {
05        if (used[i]) continue;
06        a[k] = i;
07        used[i] = true;
08        dfs(k + 1);
09        used[i] = false;
10        return;
11    }
12}

(1 分)
原创教学题 | 考点:找错:误加 return 截断同层分支
第 21 题 单选 未作答

为什么全排列的输出是字典序(123、132、213…)而不是随机顺序?

01int a[10]; bool used[10]; int n;
02void dfs(int k) {
03    if (k == n) {
04        for (int i = 0; i < n; i++) cout << a[i];
05        cout << endl;
06        return;
07    }
08    for (int i = 1; i <= n; i++) {
09        if (used[i]) continue;
10        a[k] = i;
11        used[i] = true;
12        dfs(k + 1);
13        used[i] = false;
14    }
15}

(1 分)
原创教学题 | 考点:为什么:for 从小到大保证字典序
第 22 题 单选 未作答

把全排列程序里的选择顺序反过来,输出顺序会怎样?

01for (int i = n; i >= 1; i--) {
02    if (used[i]) continue;
03    a[k] = i;
04    used[i] = true;
05    dfs(k + 1);
06    used[i] = false;
07}

(1 分)
原创教学题 | 考点:概念:搜索顺序决定输出顺序
第 23 题 单选 未作答

用「交换写法」生成全排列与用「标记数组写法」相比,正确的是?

01void perm(int k) {
02    if (k == n) { for (int i = 0; i < n; i++) cout << a[i]; cout << endl; return; }
03    for (int i = k; i < n; i++) {
04        swap(a[k], a[i]);
05        perm(k + 1);
06        swap(a[k], a[i]);
07    }
08}

(1 分)
原创教学题 | 考点:概念:交换写法 vs 标记写法
第 24 题 单选 未作答

为什么「交换写法」对 a = {1, 2, 3} 的输出不是字典序?

01void perm(int k) {
02    if (k == n) { for (int i = 0; i < n; i++) cout << a[i]; cout << endl; return; }
03    for (int i = k; i < n; i++) {
04        swap(a[k], a[i]);
05        perm(k + 1);
06        swap(a[k], a[i]);
07    }
08}

(1 分)
原创教学题 | 考点:为什么:交换写法为什么不是字典序
第 25 题 单选 未作答

用交换写法跑 a = {1, 2, 3},输出的序列是?

01void perm(int k) {
02    if (k == n) { for (int i = 0; i < n; i++) cout << a[i]; cout << endl; return; }
03    for (int i = k; i < n; i++) {
04        swap(a[k], a[i]);
05        perm(k + 1);
06        swap(a[k], a[i]);
07    }
08}

(1 分)
原创教学题 | 考点:追踪:交换写法输出序列
第 26 题 单选 未作答

n=3n = 3 的全排列输出第一个排列 123 的那一刹那,used[1]、used[2]、used[3] 的值分别是?

01int a[10]; bool used[10]; int n;
02void dfs(int k) {
03    if (k == n) {
04        for (int i = 0; i < n; i++) cout << a[i];
05        cout << endl;
06        return;
07    }
08    for (int i = 1; i <= n; i++) {
09        if (used[i]) continue;
10        a[k] = i;
11        used[i] = true;
12        dfs(k + 1);
13        used[i] = false;
14    }
15}

(1 分)
原创教学题 | 考点:追踪:输出第一个排列时 used 的状态
第 27 题 单选 未作答

全排列代码里 if (used[i]) continue; 这一行的作用是什么?

01for (int i = 1; i <= n; i++) {
02    if (used[i]) continue;
03    a[k] = i;
04    used[i] = true;
05    dfs(k + 1);
06    used[i] = false;
07}

(1 分)
原创教学题 | 考点:概念:continue 就是分支级剪枝
第 28 题 单选 未作答

「从 nn 个元素里选任意多个」是 2n2^n 种,「正好选 kk 个」是 C(n,k)C(n,k) 种。为什么搜索树结构不同?

01void sub(int i) {
02    if (i == n) { print(); return; }
03    in[i] = true; sub(i + 1); in[i] = false;
04    sub(i + 1);
05}
06
07void comb(int cnt, int start) {
08    if (cnt == k) { print(); return; }
09    for (int j = start; j < n; j++) { b[cnt] = j; comb(cnt + 1, j + 1); }
10}

(1 分)
原创教学题 | 考点:为什么:子集 2^n 与组合 C(n,k)
第 29 题 单选 未作答

对 n=2n = 2 运行子集「选/不选」代码,输出顺序是?(元素编号 1、2,空集输出空行)

01int in[10]; int n;
02void sub(int i) {
03    if (i == n) {
04        for (int j = 0; j < n; j++) if (in[j]) cout << j + 1;
05        cout << endl;
06        return;
07    }
08    in[i] = true; sub(i + 1); in[i] = false;
09    sub(i + 1);
10}

(1 分)
原创教学题 | 考点:追踪:子集选/不选输出顺序
第 30 题 单选 未作答

n=4,k=2n = 4, k = 2 运行组合代码,一共输出几个组合?前三个是什么?(元素编号 0..3)

01int b[10]; int n, k;
02void comb(int cnt, int start) {
03    if (cnt == k) { print(); return; }
04    for (int j = start; j < n; j++) { b[cnt] = j; comb(cnt + 1, j + 1); }
05}

(1 分)
原创教学题 | 考点:追踪:组合 n=4,k=2
第 31~34 题 阅读程序 (共 4 分) 未作答

题目:输入 nn(1≤n≤81 \le n \le 8),输出 1 到 nn 的全部排列,每行一个,按字典序。

01int a[10]; bool used[10]; int n;
02void dfs(int k) {
03    if (k == n) {
04        for (int i = 0; i < n; i++) cout << a[i];
05        cout << endl;
06        return;
07    }
08    for (int i = 1; i <= n; i++) {
09        if (used[i]) continue;
10        a[k] = i;
11        used[i] = true;
12        dfs(k + 1);
13        used[i] = false;
14    }
15}

31.

n=3 时程序输出几行?

(1 分)
32.

n=3 时第 2 行输出什么?

(1 分)
33.

为什么递归返回后要 used[i] = false;?

(1 分)
34.

n=1 时程序输出什么?

(1 分)
原创教学题 | 典型代码:全排列(字典序)
第 35~38 题 阅读程序 (共 4 分) 未作答

题目:输入 nn(1≤n≤61 \le n \le 6),输出集合 {1,2,…,n}\{1,2,\dots,n\} 的全部子集(每个元素选或不选),每行一个子集(元素从小到大,空子集输出空行)。

01int in[10]; int n;
02void sub(int i) {
03    if (i == n) {
04        for (int j = 0; j < n; j++) if (in[j]) cout << j + 1;
05        cout << endl;
06        return;
07    }
08    in[i] = true; sub(i + 1); in[i] = false;
09    sub(i + 1);
10}

35.

n=2 时程序输出几行?

(1 分)
36.

n=3 时第一个输出是什么?

(1 分)
37.

为什么每个元素两个分支就能覆盖全部子集?

(1 分)
38.

n=3 时包含元素 1 的子集有多少个?

(1 分)
原创教学题 | 典型代码:子集(选/不选)
第 39~41 题 阅读程序 (共 3 分) 未作答

题目:输入 n,kn, k,输出从 nn 个元素(编号 0..n-1)中取 kk 个的所有组合,每行一个,元素按从小到大、组合按字典序。

01int b[10]; int n, k;
02void comb(int cnt, int start) {
03    if (cnt == k) {
04        for (int i = 0; i < k; i++) cout << b[i];
05        cout << endl;
06        return;
07    }
08    for (int j = start; j < n; j++) {
09        b[cnt] = j;
10        comb(cnt + 1, j + 1);
11    }
12}

39.

n=4, k=2 时程序输出几行?

(1 分)
40.

为什么下一层要从 j + 1 开始而不是 start?

(1 分)
41.

k=0 时程序输出什么?

(1 分)
原创教学题 | 典型代码:组合 C(n,k)
叁

BFS:队列与最短路

28 计分点 · 每点 1 分
第 42 题 单选 未作答

广度优先搜索(BFS)一定需要用到的数据结构是?

(1 分)
原创教学题 | 考点:概念:BFS 用什么数据结构
第 43 题 单选 未作答

BFS 为什么能一层一层地推进?看下面这段 BFS 主循环:

01#include <iostream>
02#include <queue>
03#include <vector>
04using namespace std;
05vector<int> adj[105];
06int dist[105];
07void bfs(int start) {
08    for (int i = 0; i < 105; i++) dist[i] = -1;
09    dist[start] = 0;
10    queue<int> q;
11    q.push(start);
12    while (!q.empty()) {
13        int u = q.front();
14        q.pop();
15        for (int v : adj[u])
16            if (dist[v] == -1) {
17                dist[v] = dist[u] + 1;
18                q.push(v);
19            }
20    }
21}

(1 分)
原创教学题 | 考点:概念:BFS 分层推进的含义
第 44 题 单选 未作答

为什么 BFS 中第一次访问到目标状态时的层数就一定是最短步数?

01while (!q.empty()) {
02    Node u = q.front(); q.pop();
03    for (int d = 0; d < 4; d++) {
04        int nx = u.x + dx[d], ny = u.y + dy[d];
05        if (非法) continue;
06        if (step[nx][ny] != -1) continue;
07        step[nx][ny] = step[u.x][u.y] + 1;
08        q.push({nx, ny});
09    }
10}

(1 分)
原创教学题 | 考点:为什么:BFS 首达目标就是最短
第 45 题 单选 未作答

同样的迷宫,为什么用 DFS 找到终点时路径不一定最短?

01void dfs(int x, int y, int d) {
02    if (x == ex && y == ey) { ans = min(ans, d); return; }
03    for (int k = 0; k < 4; k++) {
04        int nx = x + dx[k], ny = y + dy[k];
05        if (非法) continue;
06        dfs(nx, ny, d + 1);
07    }
08}

(1 分)
原创教学题 | 考点:为什么:DFS 首达目标不保证最短
第 46 题 单选 未作答

BFS 里 step[nx][ny] != -1 判断(相当于 visited)同时起哪几个作用?

01while (!q.empty()) {
02    Node u = q.front(); q.pop();
03    for (int d = 0; d < 4; d++) {
04        int nx = u.x + dx[d], ny = u.y + dy[d];
05        if (非法) continue;
06        if (step[nx][ny] != -1) continue;
07        step[nx][ny] = step[u.x][u.y] + 1;
08        q.push({nx, ny});
09    }
10}

(1 分)
原创教学题 | 考点:概念:visited 的三大作用
第 47 题 单选 未作答

为什么 BFS/DFS 遍历图或网格时必须有 visited 标记?以下面的 BFS 为例:

01while (!q.empty()) {
02    Node u = q.front(); q.pop();
03    for (int d = 0; d < 4; d++) {
04        int nx = u.x + dx[d], ny = u.y + dy[d];
05        if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
06        if (g[nx][ny] == '#') continue;
07        step[nx][ny] = step[u.x][u.y] + 1;
08        q.push({nx, ny});
09    }
10}

(1 分)
原创教学题 | 考点:为什么:必须 visited 否则死循环
第 48 题 单选 未作答

BFS 代码里 step[nx][ny] = ...; q.push(...) 是「入队时标记」。若改成「出队时标记」(在 q.pop() 之后才检查/标记),后果是?

01while (!q.empty()) {
02    Node u = q.front(); q.pop();
03    step[u.x][u.y] = 1;
04    for (int d = 0; d < 4; d++) {
05        int nx = u.x + dx[d], ny = u.y + dy[d];
06        if (非法) continue;
07        q.push({nx, ny});
08    }
09}

(1 分)
原创教学题 | 考点:为什么:入队时标记而非出队时
第 49 题 单选 未作答

在一个 2 格直线迷宫(起点 S 在左格、右边格 E)上运行「没有 visited 标记」的 BFS,会发生什么?

(1 分)
原创教学题 | 考点:追踪:无判重时队列不收敛
第 50 题 单选 未作答

补全网格 BFS:只有「没到过」的格子才扩展,防止重复入队。

01for (int d = 0; d < 4; d++) {
02    int nx = u.x + dx[d], ny = u.y + dy[d];
03    if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
04    if (g[nx][ny] == '#') continue;
05    if (____) continue;
06    step[nx][ny] = step[u.x][u.y] + 1;
07    q.push({nx, ny});
08}

(1 分)
原创教学题 | 考点:挖空:补全网格 BFS 判重行
第 51 题 单选 未作答

3×3 迷宫,S 在 (0,0),E 在 (2,2),路径唯一:向右、向下、向右、向下。运行下面的 BFS,step[2][2] 是多少?

01step[sx][sy] = 0;
02queue<Node> q; q.push({sx, sy});
03while (!q.empty()) {
04    Node u = q.front(); q.pop();
05    for (int d = 0; d < 4; d++) {
06        int nx = u.x + dx[d], ny = u.y + dy[d];
07        if (非法) continue;
08        if (step[nx][ny] != -1) continue;
09        step[nx][ny] = step[u.x][u.y] + 1;
10        q.push({nx, ny});
11    }
12}

(1 分)
原创教学题 | 考点:追踪:二格迷宫 BFS 步数
第 52 题 单选 未作答

网格 BFS 从起点出发,第一轮扩展得到 A、B、C、D 四个邻居入队(按方向数组顺序),第二轮又从 A 扩展到 X。队列当前的顺序是?

01while (!q.empty()) {
02    Node u = q.front(); q.pop();
03    for (int d = 0; d < 4; d++) { ... q.push({nx, ny}); }
04}

(1 分)
原创教学题 | 考点:追踪:BFS 出队顺序
第 53 题 单选 未作答

BFS 的时间复杂度是?(V 为状态数、E 为转移数)

01step[sx][sy] = 0;
02queue<Node> q;
03q.push({sx, sy});
04while (!q.empty()) {
05    Node u = q.front(); q.pop();
06    for (int d = 0; d < 4; d++) {
07        if (非法) continue;
08        if (step[nx][ny] != -1) continue;
09        step[nx][ny] = step[u.x][u.y] + 1;
10        q.push({nx, ny});
11    }
12}

(1 分)
原创教学题 | 考点:概念:BFS 复杂度
第 54 题 单选 未作答

倒水问题(3 升壶和 5 升壶,每次可灌满、倒空或互相倒,问凑出目标水量最少要几步):用 BFS 求最少操作数,程序在「出队时」检查 x == c || y == c 并返回层数。起点 (0,0),目标 c,BFS 第一次弹出满足条件的状态时返回的层数表示什么?

01while (!q.empty()) {
02    int x = q.front().first, y = q.front().second;
03    q.pop();
04    if (x == c || y == c) return vis[x][y] - 1;
05    ...
06}

(1 分)
原创教学题 | 考点:追踪:状态 BFS 首次访问最短
第 55~58 题 阅读程序 (共 4 分) 未作答

01#include <iostream>
02#include <queue>
03using namespace std;
04struct Node { int x, y; };
05int n, m, sx, sy, ex, ey;
06char g[105][105];
07int step[105][105];
08const int dx[4] = {-1, 1, 0, 0};
09const int dy[4] = {0, 0, -1, 1};
10void bfs() {
11    step[sx][sy] = 0;
12    queue<Node> q;
13    q.push({sx, sy});
14    while (!q.empty()) {
15        Node u = q.front(); q.pop();
16        for (int d = 0; d < 4; d++) {
17            int nx = u.x + dx[d], ny = u.y + dy[d];
18            if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
19            if (g[nx][ny] == '#') continue;
20            if (step[nx][ny] != -1) continue;
21            step[nx][ny] = step[u.x][u.y] + 1;
22            q.push({nx, ny});
23        }
24    }
25}

55.

3×4 迷宫,起点 (0,0)、终点 (3,0),除起点外全部是空地,BFS 后 step[3][0] 是多少?

(1 分)
56.

为什么入队前判重能避免队列膨胀?

(1 分)
57.

若方向数组只有 {0,0,1,0} 表示只准向右、向下,起点 (0,0) 终点 (2,2),step[2][2] 是多少?

(1 分)
58.

判边界为什么必须用 nx < 0 全套四个条件?

(1 分)
原创教学题 | 典型代码:网格 BFS 迷宫最短路
第 59~62 题 阅读程序 (共 4 分) 未作答

01#include <iostream>
02#include <queue>
03using namespace std;
04int a, b, c;
05int vis[105][105];
06int bfs() {
07    vis[0][0] = 1;
08    queue<pair<int, int> > q;
09    q.push({0, 0});
10    while (!q.empty()) {
11        int x = q.front().first, y = q.front().second;
12        q.pop();
13        if (x == c || y == c) return vis[x][y] - 1;
14        int nxt[6][2] = {
15            {a, y}, {x, b}, {0, y}, {x, 0},
16            {max(0, x - (b - y)), min(b, x + y)},
17            {min(a, x + y), max(0, y - (a - x))}
18        };
19        for (int d = 0; d < 6; d++) {
20            int nx = nxt[d][0], ny = nxt[d][1];
21            if (vis[nx][ny]) continue;
22            vis[nx][ny] = vis[x][y] + 1;
23            q.push({nx, ny});
24        }
25    }
26    return -1;
27}

59.

容器 1 容量 3、容器 2 容量 5,目标 4 升。程序返回的最少操作数是多少?

(1 分)
60.

为什么状态可以编码成 x * (b+1) + y 作 key?

(1 分)
61.

为什么 BFS 里 x == c || y == c 而不是 &&?

(1 分)
62.

若 a=5, b=3, c=0(起点即达成目标),程序返回什么?

(1 分)
原创教学题 | 典型代码:状态 BFS 倒水问题
第 63~66 题 阅读程序 (共 4 分) 未作答

题目:n×mn \times m 棋盘,马从 (1,1)(1,1) 出发按「日」字跳,求到每个格子的最少步数(不可达输出 -1)。

01#include <iostream>
02#include <queue>
03using namespace std;
04int step[505][505];
05int n, m;
06const int dx[8] = {-2, -2, -1, -1, 1, 1, 2, 2};
07const int dy[8] = {-1, 1, -2, 2, -2, 2, -1, 1};
08void bfs() {
09    step[1][1] = 0;
10    queue<pair<int, int> > q;
11    q.push({1, 1});
12    while (!q.empty()) {
13        int x = q.front().first, y = q.front().second;
14        q.pop();
15        for (int d = 0; d < 8; d++) {
16            int nx = x + dx[d], ny = y + dy[d];
17            if (nx < 1 || nx > n || ny < 1 || ny > m) continue;
18            if (step[nx][ny] != -1) continue;
19            step[nx][ny] = step[x][y] + 1;
20            q.push({nx, ny});
21        }
22    }
23}

63.

方向数组为什么有 8 项而不是 4 项?

(1 分)
64.

为什么 BFS 能求出「最少步数」而不用 DFS?

(1 分)
65.

4×4 棋盘,从 (1,1) 到 (4,4) 的最少步数是多少?

(1 分)
66.

若把起点 step[1][1] = 0 误写成保持初值 -1,会怎样?

(1 分)
原创教学题 | 典型代码:棋盘 BFS 马的遍历
第 67 题 单选 未作答

BFS 主循环的三个要素按顺序是?

(1 分)
原创教学题 | 考点:概念:BFS 模板三要素
第 68 题 单选 未作答

为什么网格 BFS 里必须有 nx < 0 || nx >= n || ny < 0 || ny >= m 这套边界判断?

01for (int d = 0; d < 4; d++) {
02    int nx = u.x + dx[d], ny = u.y + dy[d];
03    if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
04    if (g[nx][ny] == '#') continue;
05    if (step[nx][ny] != -1) continue;
06    step[nx][ny] = step[u.x][u.y] + 1;
07    q.push({nx, ny});
08}

(1 分)
原创教学题 | 考点:为什么:网格 BFS 必须判边界
第 69 题 单选 未作答

BFS 求最短步数,终点判断放在「出队时」与「入队时」,结果一样吗?

01
02while (!q.empty()) {
03    Node u = q.front(); q.pop();
04    if (u.x == ex && u.y == ey) return step[u.x][u.y];
05    ...
06}
07
08while (!q.empty()) {
09    Node u = q.front(); q.pop();
10    ...
11    if (nx == ex && ny == ey) return step[nx][ny];
12}

(1 分)
原创教学题 | 考点:为什么:终点判断出队时与入队时
肆

Flood Fill:连通块

23 计分点 · 每点 1 分
第 70 题 单选 未作答

四连通意义下,网格中「连通块」是指?

(1 分)
原创教学题 | 考点:概念:连通块的定义
第 71 题 单选 未作答

八连通与四连通的差别在于?

(1 分)
原创教学题 | 考点:概念:四连通与八连通的定义
第 72 题 单选 未作答

4×4 网格,W 位置为:(0,0)、(0,1)、(1,1)、(2,2)、(3,2)、(3,3)。按四连通算有几块?按八连通算有几块?

01
02const int dx[4] = {-1, 1, 0, 0};
03const int dy[4] = {0, 0, -1, 1};

(1 分)
原创教学题 | 考点:追踪:两种连通定义块数不同
第 73 题 单选 未作答

2×2 网格四格全为 W,四连通下 Flood Fill 后 ans 是多少?

01for (int i = 0; i < n; i++)
02    for (int j = 0; j < m; j++)
03        if (a[i][j] == 'W') {
04            ans++;
05            flood(i, j);
06        }

(1 分)
原创教学题 | 考点:追踪:四连通 2×2 全 W 的块数
第 74 题 单选 未作答

为什么 Flood Fill 的计数逻辑「发现新块先 ans++ 再整块淹掉」能保证每块恰好计数一次?

01for (int i = 0; i < n; i++)
02    for (int j = 0; j < m; j++)
03        if (a[i][j] == 'W') {
04            ans++;
05            flood(i, j);
06        }

(1 分)
原创教学题 | 考点:为什么:计数逻辑为什么不会重复
第 75 题 单选 未作答

对 1×3 的一行 W W W 调用 flood(0,0)(四连通),flood 返回后三个格子状态是?

01void flood(int x, int y) {
02    if (x < 0 || x >= n || y < 0 || y >= m) return;
03    if (a[x][y] == '.') return;
04    a[x][y] = '.';
05    for (int d = 0; d < 4; d++)
06        flood(x + dx[d], y + dy[d]);
07}

(1 分)
原创教学题 | 考点:追踪:flood 递归方向顺序
第 76 题 单选 未作答

Flood Fill 里为什么「先 a[x][y] = '.' 再递归」,而不是「先递归完再标记」?

01void flood(int x, int y) {
02    if (x < 0 || x >= n || y < 0 || y >= m) return;
03    if (a[x][y] == '.') return;
04    a[x][y] = '.';
05    for (int d = 0; d < 4; d++)
06        flood(x + dx[d], y + dy[d]);
07}

(1 分)
原创教学题 | 考点:为什么:flood 标记为什么要先于递归
第 77 题 单选 未作答

同一张图,用 DFS 递归泛洪和用 BFS 队列泛洪,最终算出的连通块数会不同吗?下面两段分别是两种实现:

01#include <iostream>
02#include <queue>
03using namespace std;
04char a[105][105];
05int n, m;
06const int dx[4] = {-1, 1, 0, 0};
07const int dy[4] = {0, 0, -1, 1};
08void flood_dfs(int x, int y) {
09    if (x < 0 || x >= n || y < 0 || y >= m) return;
10    if (a[x][y] == '.') return;
11    a[x][y] = '.';
12    for (int d = 0; d < 4; d++)
13        flood_dfs(x + dx[d], y + dy[d]);
14}
15void flood_bfs(int sx, int sy) {
16    queue<pair<int, int> > q;
17    q.push({sx, sy});
18    a[sx][sy] = '.';
19    while (!q.empty()) {
20        int x = q.front().first, y = q.front().second;
21        q.pop();
22        for (int d = 0; d < 4; d++) {
23            int nx = x + dx[d], ny = y + dy[d];
24            if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
25            if (a[nx][ny] == '.') continue;
26            a[nx][ny] = '.';
27            q.push({nx, ny});
28        }
29    }
30}

(1 分)
原创教学题 | 考点:为什么:DFS 泛洪与 BFS 泛洪结果相同
第 78 题 单选 未作答

5×5 网格只有中间的 3×3 是 W(其余都是 .)。从中心 W 发起 flood,四连通下会淹掉多少格?

01a[x][y] = '.';
02for (int d = 0; d < 4; d++) flood(x + dx[d], y + dy[d]);

(1 分)
原创教学题 | 考点:追踪:泛洪起点在块内非角落
第 79 题 单选 未作答

Flood Fill(泛洪)的本质操作是?

(1 分)
原创教学题 | 考点:概念:泛洪本质
第 80 题 单选 未作答

4×4 网格,W 在 (0,0) 和 (3,3),其余为 .。四连通 Flood Fill 后 ans 是多少?

01for (int i = 0; i < n; i++)
02    for (int j = 0; j < m; j++)
03        if (a[i][j] == 'W') { ans++; flood(i, j); }

(1 分)
原创教学题 | 考点:追踪:障碍分隔成两块
第 81~84 题 阅读程序 (共 4 分) 未作答

01#include <iostream>
02using namespace std;
03char a[105][105];
04int n, m, ans;
05const int dx[4] = {-1, 1, 0, 0};
06const int dy[4] = {0, 0, -1, 1};
07void flood(int x, int y) {
08    if (x < 0 || x >= n || y < 0 || y >= m) return;
09    if (a[x][y] == '.') return;
10    a[x][y] = '.';
11    for (int d = 0; d < 4; d++)
12        flood(x + dx[d], y + dy[d]);
13}
14int main() {
15    cin >> n >> m;
16    for (int i = 0; i < n; i++)
17        for (int j = 0; j < m; j++)
18            cin >> a[i][j];
19    for (int i = 0; i < n; i++)
20        for (int j = 0; j < m; j++)
21            if (a[i][j] == 'W') {
22                ans++;
23                flood(i, j);
24            }
25    cout << ans << endl;
26    return 0;
27}

81.

2×2 全为 W,程序输出多少?

(1 分)
82.

为什么主循环要在格子为 W 时才计数?

(1 分)
83.

把方向数组从 4 项改成 8 项(八连通),块数会?

(1 分)
84.

若把主循环 if (a[i][j] == 'W') 误写成 if (a[i][j] == '.'),程序输出多少?

(1 分)
原创教学题 | 典型代码:细胞计数(四连通)
第 85~88 题 阅读程序 (共 4 分) 未作答

题目:n×mn \times m 网格,. 为水、# 为陆地,求最大陆地块的面积(格子数)。陆地块 = 四连通的 # 组成的最大区域。

01#include <iostream>
02using namespace std;
03char g[105][105];
04int n, m, cur;
05const int dx[4] = {-1, 1, 0, 0};
06const int dy[4] = {0, 0, -1, 1};
07void dfs(int x, int y) {
08    if (x < 0 || x >= n || y < 0 || y >= m) return;
09    if (g[x][y] != '#') return;
10    g[x][y] = '.';
11    cur++;
12    for (int d = 0; d < 4; d++)
13        dfs(x + dx[d], y + dy[d]);
14}

85.

cur 每次统计一块的面积,应该在什么时候重置为 0?

(1 分)
86.

为什么必须先标 . 再递归?

(1 分)
87.

3×3 网格只有中心一格为 #,其余全为 .,最大陆地面积是多少?

(1 分)
88.

用 BFS 实现本题,结果会不同吗?

(1 分)
原创教学题 | 典型代码:最大连通块面积
第 89~90 题 阅读程序 (共 2 分) 未作答

题目:n×mn \times m 网格,W 为水、. 为地。八连通意义下水的连通块(湖泊)有几个?八连通:含对角相邻。

01#include <iostream>
02using namespace std;
03char a[105][105];
04int n, m, ans;
05const int dx[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
06const int dy[8] = {-1, 0, 1, -1, 1, -1, 0, 1};
07void flood(int x, int y) {
08    if (x < 0 || x >= n || y < 0 || y >= m) return;
09    if (a[x][y] == '.') return;
10    a[x][y] = '.';
11    for (int d = 0; d < 8; d++)
12        flood(x + dx[d], y + dy[d]);
13}

89.

3×3 网格 W 位于四个角,八连通湖泊数是多少?

(1 分)
90.

为什么八连通用 8 项方向数组?

(1 分)
原创教学题 | 典型代码:八连通湖泊计数
第 91 题 单选 未作答

补全 Flood Fill:进入一个格子后要「先 ____ 再递归」,并用「先判越界再访问」的顺序。

01void flood(int x, int y) {
02    if (x < 0 || x >= n || y < 0 || y >= m) return;
03    if (a[x][y] == '.') return;
04    ____;
05    for (int d = 0; d < 4; d++)
06        flood(x + dx[d], y + dy[d]);
07}

(1 分)
原创教学题 | 考点:挖空:泛洪标记时机
第 92 题 单选 未作答

Flood Fill 里如果把标记行 a[x][y] = '.' 删掉,会发生什么?

01void flood(int x, int y) {
02    if (x < 0 || x >= n || y < 0 || y >= m) return;
03    if (a[x][y] == '.') return;
04    a[x][y] = '.';
05    for (int d = 0; d < 4; d++) flood(x + dx[d], y + dy[d]);
06}

(1 分)
原创教学题 | 考点:为什么:泛洪必须标记
伍

剪枝、复杂度与算法选型

26 计分点 · 每点 1 分
第 93 题 单选 未作答

搜索的总时间如何估算?

(1 分)
原创教学题 | 考点:概念:搜索复杂度口径
第 94 题 单选 未作答

搜索里「剪枝」指的是?

(1 分)
原创教学题 | 考点:概念:剪枝的定义
第 95 题 单选 未作答

子集和的代码加了 if (sum > t) return;。为什么这一行有时能把超时的程序救回来?

01void dfs(int i, int sum) {
02    if (i == n) { if (sum == t) ok = true; return; }
03    if (sum > t) return;
04    dfs(i + 1, sum);
05    dfs(i + 1, sum + w[i]);
06}

(1 分)
原创教学题 | 考点:为什么:剪枝为什么能省这么多时间
第 96 题 单选 未作答

fib(5)(朴素递归,不记忆化)一共调用 fib 多少次?

01int fib(int n) {
02    if (n <= 1) return n;
03    return fib(n - 1) + fib(n - 2);
04}

(1 分)
原创教学题 | 考点:追踪:斐波那契朴素递归调用次数
第 97 题 单选 未作答

同样求 fibm(5)(记忆化版),fibm 被调用的次数是?

01int f[100];
02int fibm(int n) {
03    if (n <= 1) return n;
04    if (f[n] != -1) return f[n];
05    return f[n] = fibm(n - 1) + fibm(n - 2);
06}

(1 分)
原创教学题 | 考点:追踪:斐波那契记忆化调用次数
第 98 题 单选 未作答

为什么记忆化能把斐波那契从 O(2n)O(2^n) 降到 O(n)O(n)?

01int f[100];
02int fibm(int n) {
03    if (n <= 1) return n;
04    if (f[n] != -1) return f[n];
05    return f[n] = fibm(n - 1) + fibm(n - 2);
06}

(1 分)
原创教学题 | 考点:为什么:记忆化为什么有效
第 99 题 单选 未作答

记忆化搜索能加速的前提是?

(1 分)
原创教学题 | 考点:概念:记忆化适用的条件
第 100 题 单选 未作答

状态空间巨大(如 101810^{18} 个不同状态)且每条路径状态互不重叠时,记忆化会怎样?

(1 分)
原创教学题 | 考点:为什么:记忆化什么时候无效
第 101 题 单选 未作答

子集和:n=5n = 5,w = {8, 9, 7, 2, 1},t = 10。代码带 if (sum > t) return; 剪枝。搜索会不会「提前」跳过以 8 开头的子树?(w 全为正数)

01void dfs(int i, int sum) {
02    if (i == n) { if (sum == t) ok = true; return; }
03    if (sum > t) return;
04    dfs(i + 1, sum);
05    dfs(i + 1, sum + w[i]);
06}

(1 分)
原创教学题 | 考点:追踪:子集和剪枝的效果
第 102 题 单选 未作答

同样一个剪枝搜索,为什么「先搜分支少/约束强」的方向通常更快?

(1 分)
原创教学题 | 考点:为什么:先搜约束强的分支更快
第 103 题 单选 未作答

求「最长路径」的搜索里,「最优性剪枝」指的是?

(1 分)
原创教学题 | 考点:概念:最优性剪枝
第 104 题 单选 未作答

为什么最优性剪枝必须用「上界 ≤ 当前最优」剪,而不是「当前值 ≤ 当前最优」剪?

(1 分)
原创教学题 | 考点:为什么:最优性剪枝为什么必须用上界
第 105 题 单选 未作答

「走迷宫(网格上每步走到相邻空地)求最短路」该用哪种搜索?「八皇后(在 8×88 \times 8 棋盘上每行放一个皇后,要求任意两个皇后不同列、不同对角线,枚举全部摆法)」又该用哪种搜索?

(1 分)
原创教学题 | 考点:为什么:DFS 还是 BFS 选型
第 106 题 单选 未作答

只判断「A 能不能走到 B」(不要求最短),DFS 和 BFS 哪个能用?

(1 分)
原创教学题 | 考点:概念:可达性判断两种都能用
第 107 题 单选 未作答

状态空间巨大时,为什么 BFS 可能内存爆掉而 DFS 不会?对比两种实现的「待处理」存储:

01#include <queue>
02#include <vector>
03using namespace std;
04vector<int> adj[105];
05bool vis[105];
06void bfs(int s) {
07    queue<int> q;
08    q.push(s);
09    vis[s] = true;
10    while (!q.empty()) {
11        int u = q.front();
12        q.pop();
13        for (int v : adj[u])
14            if (!vis[v]) {
15                vis[v] = true;
16                q.push(v);
17            }
18    }
19}
20void dfs_stack(int s) {
21    vector<int> st;
22    st.push_back(s);
23    vis[s] = true;
24    while (!st.empty()) {
25        int u = st.back();
26        st.pop_back();
27        for (int v : adj[u])
28            if (!vis[v]) {
29                vis[v] = true;
30                st.push_back(v);
31            }
32    }
33}

(1 分)
原创教学题 | 考点:为什么:BFS 内存 vs DFS 内存
第 108 题 单选 未作答

关于搜索与数据结构的关系,正确的是?

(1 分)
原创教学题 | 考点:概念:DFS↔栈 BFS↔队列
第 109 题 单选 未作答

每秒能处理约 10810^8 个状态。全排列(把 1∼n1 \sim n 的所有排列逐个枚举):n=20n = 20 时共 20!≈2.4×101820! \approx 2.4 \times 10^{18} 种,能跑完吗?

(1 分)
原创教学题 | 考点:追踪:n=20 全排列可行性
第 110~113 题 阅读程序 (共 4 分) 未作答

01int w[20];
02int n, t;
03bool ok = false;
04void dfs(int i, int sum) {
05    if (i == n) {
06        if (sum == t) ok = true;
07        return;
08    }
09    if (sum > t) return;
10    dfs(i + 1, sum);
11    dfs(i + 1, sum + w[i]);
12}

110.

n=3, w={1,2,3}, t=3,程序结束时 ok 为?

(1 分)
111.

为什么 sum > t 时可以直接 return 而不会漏答案?

(1 分)
112.

w={1,2,3}, t=6,sum > t 剪枝会剪掉多少分支?

(1 分)
113.

若 w 允许负数,sum > t 剪枝还正确吗?

(1 分)
原创教学题 | 典型代码:子集和可行性剪枝
第 114~117 题 阅读程序 (共 4 分) 未作答

01int fib(int n) {
02    if (n <= 1) return n;
03    return fib(n - 1) + fib(n - 2);
04}
05
06int f[100];
07int fibm(int n) {
08    if (n <= 1) return n;
09    if (f[n] != -1) return f[n];
10    return f[n] = fibm(n - 1) + fibm(n - 2);
11}

114.

fib(6)(朴素递归)一共调用 fib 多少次?

(1 分)
115.

fibm(6)(记忆化)真正需要计算的 n 有几个?(不含缓存命中)

(1 分)
116.

为什么 fibm 里的 f[n] != -1 判断是「查缓存」?

(1 分)
117.

在计算 fibm(4) 的过程中,fibm(2) 已经被 fibm(3) 算过并存进 f[2]。此时再调 fibm(2) 会发生什么?

(1 分)
原创教学题 | 典型代码:斐波那契朴素 vs 记忆化
第 118 题 单选 未作答

下面哪一组完整覆盖了常见的剪枝类型?

(1 分)
原创教学题 | 考点:概念:三类剪枝
陆

综合:常见错误与真题形态

19 计分点 · 每点 1 分
第 119 题 单选 未作答

下面这段 BFS 有一个严重问题。找出它:

01while (!q.empty()) {
02    int x = q.front().first, y = q.front().second;
03    for (int d = 0; d < 4; d++) {
04        int nx = x + dx[d], ny = y + dy[d];
05        if (非法) continue;
06        step[nx][ny] = step[x][y] + 1;
07        q.push({nx, ny});
08    }
09}

(1 分)
原创教学题 | 考点:找错:忘出队/忘标记混合
第 120 题 单选 未作答

子集和代码里 if (sum > t) return; 放在两个递归调用的前面。若 w 全部为正数,这个剪枝会「漏掉答案」吗?

01void dfs(int i, int sum) {
02    if (i == n) { if (sum == t) ok = true; return; }
03    if (sum > t) return;
04    dfs(i + 1, sum);
05    dfs(i + 1, sum + w[i]);
06}

(1 分)
原创教学题 | 考点:追踪:循环不变式判断输出
第 121 题 单选 未作答

「忘恢复现场」和「忘标记」在回溯搜索里的后果有什么不同?第一段删掉了「恢复现场」一行,第二段删掉了「标记」一行:

01int a[10]; bool used[10]; int n;
02void dfs(int k) {
03    if (k == n) {
04        for (int i = 0; i < n; i++) cout << a[i];
05        cout << endl;
06        return;
07    }
08    for (int i = 1; i <= n; i++) {
09        if (used[i]) continue;
10        a[k] = i;
11        used[i] = true;
12        dfs(k + 1);
13    }
14}

01int a[10]; bool used[10]; int n;
02void dfs(int k) {
03    if (k == n) {
04        for (int i = 0; i < n; i++) cout << a[i];
05        cout << endl;
06        return;
07    }
08    for (int i = 1; i <= n; i++) {
09        if (used[i]) continue;
10        a[k] = i;
11        dfs(k + 1);
12        used[i] = false;
13    }
14}

(1 分)
原创教学题 | 考点:为什么:忘恢复现场 vs 忘标记后果不同
第 122 题 单选 未作答

带限制的全排列:n = 3,限制是「第 k 位数字不能等于前一位数字加 1」(即相邻两个数不能相差恰为 1 且后者大 1)。程序输出多少?

01if (k > 1 && i == p[k - 1] + 1) continue;

(1 分)
原创教学题 | 考点:追踪:限制条件下的排列计数
第 123 题 单选 未作答

用「画递归树」法读下面的 DFS:n = 2 时输出多少?

01int a[10]; bool used[10]; int n;
02void dfs(int k) {
03    if (k == n) { ans++; return; }
04    for (int i = 1; i <= n; i++) {
05        if (used[i]) continue;
06        used[i] = true;
07        dfs(k + 1);
08        used[i] = false;
09    }
10}

(1 分)
原创教学题 | 考点:追踪:DFS 递归树追踪法(小数据)
第 124 题 单选 未作答

阅读一段 DFS 回溯代码时,最有效的方法是?

(1 分)
原创教学题 | 考点:概念:阅读 DFS 程序的正确方法
第 125 题 单选 未作答

CSP 初赛常考「DFS 阅读程序 + 判断/选择」题型。这类题的核心考点通常是?

(1 分)
原创教学题 | 考点:概念:真题形态——阅读程序考什么
第 126 题 单选 未作答

下面这段 BFS 求起点到终点最短路,哪里错了?

01while (!q.empty()) {
02    int x = q.front().first, y = q.front().second;
03    q.pop();
04    if (x == ex && y == ey) break;
05    for (int d = 0; d < 4; d++) {
06        int nx = x + dx[d], ny = y + dy[d];
07        if (非法) continue;
08        if (step[nx][ny] != -1) continue;
09        step[nx][ny] = step[x][y] + 1;
10        q.push({nx, ny});
11    }
12}
13cout << step[ex][ey] << endl;

(1 分)
原创教学题 | 考点:找错:终点判断位置
第 127 题 单选 未作答

判断「从起点能否到终点」用 DFS 或 BFS 都能完成。为什么都行?下面分别是两种遍历的骨架:

01#include <iostream>
02#include <queue>
03#include <vector>
04using namespace std;
05vector<int> adj[105];
06bool vis[105];
07void dfs(int u) {
08    vis[u] = true;
09    for (int v : adj[u])
10        if (!vis[v]) dfs(v);
11}
12void bfs(int s) {
13    queue<int> q;
14    q.push(s);
15    vis[s] = true;
16    while (!q.empty()) {
17        int u = q.front();
18        q.pop();
19        for (int v : adj[u])
20            if (!vis[v]) {
21                vis[v] = true;
22                q.push(v);
23            }
24    }
25}

(1 分)
原创教学题 | 考点:为什么:可达性问题 DFS/BFS 皆可但实现不同
第 128 题 单选 未作答

删掉子集和代码里的 if (sum > t) return;,对「ok 最终值」有什么影响?(w 全正)

01void dfs(int i, int sum) {
02    if (i == n) { if (sum == t) ok = true; return; }
03    dfs(i + 1, sum);
04    dfs(i + 1, sum + w[i]);
05}

(1 分)
原创教学题 | 考点:追踪:删掉剪枝行对答案的影响
第 129 题 单选 未作答

BFS 里「层」和 DFS 里「深度」的关系是?

(1 分)
原创教学题 | 考点:概念:BFS 层数 vs DFS 深度术语
第 130~133 题 阅读程序 (共 4 分) 未作答

01#include <cstdio>
02bool flag[27];
03int n;
04int p[27];
05int ans = 0;
06void dfs(int k) {
07    if (k == n + 1) {
08        ans++;
09        return;
10    }
11    for (int i = 1; i <= n; i++) {
12        if (flag[i]) continue;
13        if (k > 1 && i == p[k - 1] + 1) continue;
14        p[k] = i;
15        flag[i] = true;
16        dfs(k + 1);
17        flag[i] = false;
18    }
19}
20int main() {
21    scanf("%d", &n);
22    dfs(1);
23    printf("%d\n", ans);
24    return 0;
25}

130.

n=3 时程序输出的 ans 是多少?

(1 分)
131.

dfs 运行过程中,k 的取值恒满足 1≤k≤n+11 \le k \le n+1,对吗?

(1 分)
132.

删掉恢复现场行 flag[i] = false;,对 n=3 的答案有影响吗?

(1 分)
133.

删掉判重行 if (flag[i]) continue;,n=2 时程序输出多少?

(1 分)
原创教学题 | 典型代码:DFS 回溯·限制条件(真题形态)
第 134~137 题 阅读程序 (共 4 分) 未作答

题目:阅读程序。d 是 nn 行 2 列的数组。dfs(n, sum) 不断把相邻两行「合并」(前一行加后一行的对应列),直到只剩 1 行,枚举所有合并顺序并求加权和的最大值。

01#include <cstdio>
02int n;
03int d[50][2];
04int ans;
05void dfs(int n, int sum) {
06    if (n == 1) {
07        if (sum > ans) ans = sum;
08        return;
09    }
10    for (int i = 1; i < n; i++) {
11        int a = d[i - 1][0], b = d[i - 1][1];
12        int x = d[i][0], y = d[i][1];
13        d[i - 1][0] = a + x;
14        d[i - 1][1] = b + y;
15        for (int j = i; j < n - 1; j++) {
16            d[j][0] = d[j + 1][0];
17            d[j][1] = d[j + 1][1];
18        }
19        int s = a + x + abs(b - y);
20        dfs(n - 1, sum + s);
21        for (int j = n - 1; j > i; j--) {
22            d[j][0] = d[j - 1][0];
23            d[j][1] = d[j - 1][1];
24        }
25        d[i - 1][0] = a;
26        d[i - 1][1] = b;
27        d[i][0] = x;
28        d[i][1] = y;
29    }
30}

134.

这个程序的功能是?

(1 分)
135.

若输入 n=1,程序输出什么?

(1 分)
136.

输入的所有数都是 0 时,程序输出多少?

(1 分)
137.

程序的输出一定不小于输入的任意一个 d[i][0] 或 d[i][1] 吗?

(1 分)
原创教学题 | 典型代码:DFS 阅读·枚举合并顺序(真题形态)
柒

真题检验 · 历年真题(原样罗列)

1 道真题 | 每题 1 分
第 138~143 题 阅读程序 (共 6 分) 未作答

1  #include <algorithm>
2  #include <iostream>
3  using namespace std;
4 
5  int n;
6  int d[50][2];
7  int ans;
8 
9  void dfs(int n, int sum) {
10      if (n == 1) {
11          ans = max(sum, ans);
12          return;
13      }
14      for (int i = 1; i < n; ++i) {
15          int a = d[i - 1][0], b = d[i - 1][1];
16          int x = d[i][0], y = d[i][1];
17          d[i - 1][0] = a + x;
18          d[i - 1][1] = b + y;
19          for (int j = i; j < n - 1; ++j)
20              d[j][0] = d[j + 1][0], d[j][1] = d[j + 1][1];
21          int s = a + x + abs(b - y);
22          dfs(n - 1, sum + s);
23          for (int j = n - 1; j > i; --j)
24              d[j][0] = d[j - 1][0], d[j][1] = d[j - 1][1];
25          d[i - 1][0] = a, d[i - 1][1] = b;
26          d[i][0] = x, d[i][1] = y;
27      }
28  }
29 
30  int main() {
31      cin >> n;
32      for (int i = 0; i < n; ++i)
33          cin >> d[i][0];
34      for (int i = 0; i < n; ++i)
35          cin >> d[i][1];
36      ans = 0;
37      dfs(n, 0);
38      cout << ans << endl;
39      return 0;
40  }

假设输入的 nn 是不超过 5050 的正整数,d[i][0]、d[i][1] 都是不超过 1000010000 的正整数,完成下面的判断题和单选题。

138.

若输入 nn 为 00,此程序可能会死循环或发生运行错误。( )

(1 分)
139.

若输入 nn 为 2020,接下来的输入全为 00,则输出为 00。( )

(1 分)
140.

输出的数一定不小于输入的 d[i][0] 和 d[i][1] 的任意一个。( )

(1 分)
141.

若输入的 nn 为 2020,接下来的输入是 2020 个 99 和 2020 个 00,则输出为( )。

(1 分)
142.

若输入的 nn 为 3030,接下来的输入是 3030 个 00 和 3030 个 55,则输出为( )。

(1 分)
143.

若输入的 nn 为 1515,接下来的输入是 1515 到 11,以及 1515 到 11,则输出为( )。

(1 分)
CSP-J 2020 · 阅读程序 第28-28-33题 | 知识点 搜索