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 行的 "flagi=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(flagi) 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 行的 "flagi=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(flagi) 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。

相关推荐
hongyucai22 分钟前
详解rlinf强化学习四步曲
人工智能·python·算法·架构
变量未定义~23 分钟前
ST表-龙骑士军团【算法赛】
数据结构·算法
小帽子_12343 分钟前
储能 SOC/SOH 精准估算技术:储能工况下算法优化与误差修正方案
算法
hhlongg1 小时前
FFT分析
算法
水龙吟啸1 小时前
华为2026.6.17机考选择题+编程题【速刷敲黑板】
人工智能·深度学习·算法·华为
凌波粒1 小时前
LeetCode--53. 最大子序和(贪心算法)
算法·leetcode·贪心算法
Hesionberger2 小时前
快速求解完全平方数的最少数量
开发语言·数据结构·python·算法·leetcode·c#
c238562 小时前
《序列 DP:C++ 中的“最长”套路与编辑距离》
c++·算法·动态规划
aqiu1111112 小时前
【算法日记 19】LeetCode 1. 两数之和:梦开始的地方,哈希表的降维打击
算法·leetcode·职场和发展