CSP-S 2025 提高级 第一轮(初赛) 阅读程序(1)

CSP-S 2025 提高级 第一轮(初赛) 阅读程序(1)

【题目】

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

判断题

  1. (1 分)当输入的 n=3n=3n=3 的时候,程序输出的答案为 333。

    A. 正确

    B. 错误

  2. 在 dfs 函数运行过程中,kkk 的取值会满足 1≤k≤n+11\le k\le n+11≤k≤n+1。

    A. 正确

    B. 错误

  3. 删除第 191919 行的 "flag[i]=false;",对答案不会产生影响。

    A. 正确

    B. 错误

单选题

  1. 当输入的 n=4n=4n=4 的时候,程序输出的答案为( )。

    A. 11

    B. 12

    C. 24

    D. 9

  2. 如果因为某些问题,导致程序运行到第 252525 行的 dfsdfsdfs 函数之前,数组 ppp 的初值并不全为 000,则对程序的影响是( )。

    A. 输出的答案比原答案更小

    B. 无法确定能输出的答案

    C. 程序可能陷入死循环

    D. 没有影响

  3. 假如删去第 141414 行的 "if(flag[i]) continue;",输入 333,得到的输出答案是( )。

    A. 27

    B. 3

    C. 16

    D. 12

【题目难度】:D

【题目考点】

1. 深搜回溯

【题目解析】

cpp 复制代码
23 int main() {
24     scanf("%d", &n);
25     dfs(1);
26     printf("%d\n", ans);
27     return 0;
28 }

输入nnn,而后调用深搜函数,从111开始进行深搜,搜索结束后最后输出结果ansansans。

cpp 复制代码
13     for (int i = 1; i <= n; ++i) {
14         if (flag[i]) continue;
15         if (k > 1 && i == p[k - 1] + 1) continue;
16         p[k] = i;
17         flag[i] = true;
18         dfs(k + 1);
19         flag[i] = false;
20     }

看dfs中的一般情况,iii从1循环到nnn,如果flag[i]为真,则continue,即直接开始下一次循环。先不看第15行,下面就是深搜求全排列的模板。当前在确定ppp数组中的第kkk个数,flag[i]表示数值iii是否已使用过。

  • 如果数值iii已经使用过,则接下来不用iii,这是一个可行性剪枝。
  • 否则就将p[k]设为iii,而后将iii设为已使用过,即flag[i] = true,继续搜索确定ppp数组第k+1k+1k+1个数,递归调用dfs(k+1),调用结束后,将状态还原,再将iii设为未使用过,即flag[i] = false

第15行也是一项剪枝,如果k>1k > 1k>1而且i == p[k-1]+1,就不将p[k]设为iii,限定k>1k>1k>1的原因是后面要取ppp数组下标k−1k-1k−1位置,如果k=1k=1k=1,那么k−1k-1k−1为0,p[0]不是已确定的ppp序列中的元素。当前要确定的是p[k],那么p[k-1]就是当前这一项的前一项。iii是p[k]待设定的值。那么这句话的意思是:如果当前这一项的值iii比前一项p[k-1]大1,那么就不将p[k]设为iii,也就是说在搜索全排列的过程中,排除了相邻两数后面的数比前面的数大1的情况

cpp 复制代码
09     if (k == n + 1){
10         ++ ans;
11         return;
12     }

递归出口,当kkk为n+1n+1n+1时,p[1]~p[k]都已经设好了值,存在一个满足条件的排列,ansansans计数增加。

该题求解的问题是:输入nnn,求1∼n1\sim n1∼n的排列中,不存在下一项比前一项大1的情况的排列的数量。

判断题

16. 当输入的 n=3n=3n=3 的时候,程序输出的答案为 333。
A. 正确
B. 错误

正确答案:A

按照字典序依次写出1∼31\sim 31∼3的全排列,排除其中存在下一项比前一项大1的排列:
1,2,31,2,31,2,3:不可行。
1,3,21,3,21,3,2:可行。
2,1,32,1,32,1,3:可行。
2,3,12,3,12,3,1:不可行。
3,1,23,1,23,1,2:不可行
3,2,13,2,13,2,1:可行

共3个可行的排列,因此程序会输出3,本题叙述正确。

17. 在 dfs 函数运行过程中,kkk 的取值会满足 1≤k≤n+11\le k\le n+11≤k≤n+1。
A. 正确
B. 错误

正确答案:A

开始调用时传入实参1,形参kkk的值为1。kkk为1∼n1\sim n1∼n时都会进行递归调用dfs(k+1),kkk为n+1n+1n+1时进入递归出口。因此kkk 的取值满足 1≤k≤n+11\le k\le n+11≤k≤n+1,本题叙述正确。

18. 删除第 191919 行的 "flag[i]=false;",对答案不会产生影响。
A. 正确
B. 错误

正确答案:B

如果删除flag[i] = false,则深搜回溯缺少了回溯的过程,已经如果使用过数iii,在不使用iii时,不会将iii设为未使用过,下一次可以使用iii时就无法再使用iii。

比如当输入nnn为3时,首先dfs(1)中确定了p[1]=1flag[1]=true。而后递归调用dfs(2),确定了p[2]=2, flag[2]=true,接着递归调用dfs(3),确定了p[3]=3, flag[3] = true,而后调用dfs(4),进入递归出口。回退到dfs(3),此时没有将flag[3]设为flase。再回退到dfs(2),这时iii变为3,判断flag[3]为真,直接进行下一次循环,无法将p[2]设为3。这样就无法找到可行的1,3,21,3,21,3,2这一排列,会导致计数减少,影响最值答案。因此本题叙述错误。

单选题

  1. 当输入的 n=4n=4n=4 的时候,程序输出的答案为( )。
    A. 11
    B. 12
    C. 24
    D. 9

正确答案:A

按照字典序依次查看1∼41\sim 41∼4的全排列,筛选出其中不存在下一项比前一项大1的排列。

可以先枚举前两个数的排列,再看后两个数可行的方案

第1、2个数 第3、4个数
1,2 不可行
1,3 4,2
1,4 3,2
2,1 4,3
2,3 不可行
2,4 1,3或3,1
3,1 4,2
3,2 1,4或4,1
3,4 不可行
4,1 3,2
4,2 1,3
4,3 2,1

共11种可行的排列,本题选A。

  1. 如果因为某些问题,导致程序运行到第 252525 行的 dfsdfsdfs 函数之前,数组 ppp 的初值并不全为 000,则对程序的影响是( )。
    A. 输出的答案比原答案更小
    B. 无法确定能输出的答案
    C. 程序可能陷入死循环
    D. 没有影响

正确答案:D

每次确定第kkk位置的值,都会使用当前确定的值iii覆盖p[k]的值。在确定p[k]时,可能用到的p[k-1]位置的值是这一次dfs中先前确定的值,与ppp数组的初值无关,因此ppp的初值是否为000并不影响程序,选D。

  1. 假如删去第 141414 行的 "if(flag[i]) continue;",输入 333,得到的输出答案是( )。
    A. 27
    B. 3
    C. 16
    D. 12

正确答案:C

如果删去if(flag[i]) continue;,那么即便数值iii在先前已经使用过,还可以再次使用。ppp数组中可以同时存在相同的数值,但还是要满足不存在下一项比前一项大1的情况。

按字典序枚举所有由1∼31\sim 31∼3生成的可能存在重复元素的序列,排除存在下一项比前一项大1的序列,得到的可行的排列有:
1,1,11,1,11,1,1
1,1,31,1,31,1,3
1,3,11,3,11,3,1
1,3,21,3,21,3,2
1,3,31,3,31,3,3
2,1,12,1,12,1,1
2,1,32,1,32,1,3
2,2,12,2,12,2,1
2,2,22,2,22,2,2
3,1,13,1,13,1,1
3,1,33,1,33,1,3
3,2,13,2,13,2,1
3,2,23,2,23,2,2
3,3,13,3,13,3,1
3,3,23,3,23,3,2
3,3,33,3,33,3,3

共16个可行的排列,选C。

相关推荐
小O的算法实验室1 小时前
2026年IEEE TEVC,知识引导的竞争进化算法用于多解传感器-武器-目标分配问题,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
khalil10202 小时前
代码随想录算法训练营Day-46 动态规划13 | 647. 回文子串、516.最长回文子序列、动态规划总结
数据结构·c++·算法·leetcode·动态规划·回文子串·回文子序列
学习3人组2 小时前
柔性排产时序算法+中间过程+阶段目标 细化表格
算法·mes
he___H2 小时前
算法快与慢--哈希+双指针
算法·leetcode·哈希算法
呃呃本2 小时前
算法题(回溯)
算法
刀法如飞2 小时前
Rust数组去重的20种实现方式,AI时代用不同思路解决问题
人工智能·算法·ai编程
yxc_inspire2 小时前
25年CCPC福建邀请赛补题
学习·算法
Raink老师2 小时前
用100道题拿下你的算法面试(链表篇-4):合并 K 个有序链表
算法·链表·面试
Mr_pyx2 小时前
【LeetHOT100】二叉树的中序遍历——Java多解法详解
java·开发语言·深度优先