信息学奥赛初赛天天练-53-CSP-J2019阅读程序2-模拟算法在数组中典型应用

信息学奥赛初赛天天练-53-CSP-J2019阅读程序2-模拟算法在数组中典型应用
PDF文档公众号回复关键字:20240802

2019 CSP-J 阅读程序2

1阅读程序(程序输入不超过数组或字符串定义的范围;判断题正确填 √,错误填 ×。除特殊说明外,判断题 1.5 分,选择题 3 分,共计 40 分)

假设输入的n和m都是正整数,x和y都是在[1, n]的范围内的整数,完成下面的判断题和选择题

01 #include<cstdio>
02 using namespace std;
03 int n, m;
04 int a[100], b[100];
05  
06 int main() {
07     scanf("%d%d", &n, &m);
08     for (int i = 1; i <= n; ++i)//对a和b数组的前n项置为0 
09         a[i] = b[i] = 0;
10     for (int i = 1; i <= m; ++i) {//录入m个x和y 
11         int x, y;
12         scanf("%d%d", &x, &y);
13         if (a[x] < y && b[y] < x) {//如果新录入x有相同的y比之前大,重新赋值,y也一样 
14             if (a[x] > 0)//x录入过相同的  
15                 b[a[x]] = 0;//对b数组对应a[x]对应值改为0,后续重新赋值 
16             if (b[y] > 0)//y录入过相同的  
17                 a[b[y]] = 0;//对a数组对应b[y]对应值改为0,后续重新赋值 
18             a[x] = y;//对x重新赋值 
19             b[y] = x;//对y重新赋值 
20         }
21     }
22     int ans = 0;//统计a和b数组为0的个数 
23     for (int i = 1; i <= n; ++i) {
24         if (a[i] == 0)
25             ++ans;
26         if (b[i] == 0)
27             ++ans;
28     }
29     printf("%d", ans);
30     return 0;
31 }

1 当m>0时,输出的值一定小于2n。( )

2 执行完第27行的"++ans"时,ans —定是偶数。( )

3 a[i]和b[i]不可能同时大于0。( )

4 右程序执行到第13行时,x总是小于y,那么第15行不会被执行。( )

5 若m个x两两不同,且m个y两两不同,则输出的值为( )

A 2n-2m

B 2n+2

C 2n-2

D 2n

6 若m个x两两不同,且m个y都相等,则输出的值为( )

A 2n-2

B 2n

C 2m

D 2n-2m

2 相关知识点

在信息学竞赛初赛中,模拟算法是一种常用的解题策略,尤其适合于处理逻辑复杂或难以直接推理的问题。以下是结合您提供的要点扩展的模拟算法解题技巧:

大致观察程序逻辑

在深入分析之前,先快速浏览整个程序,理解其大致结构和流程。

识别出主要的变量、函数和控制结构(如循环、条件语句)。

大胆猜测程序逻辑

基于观察到的结构,尝试推测程序的功能和每个部分可能的作用。

这种猜测不需要完全准确,但可以帮助你确定模拟的重点区域。

使用较小数模拟

为了简化计算和理解,可以从较小的输入值开始模拟程序的执行。

通过观察小输入值下的程序行为,可以逐步揭示其内部逻辑。

根据问题分析关键程序

仔细阅读题目描述,理解问题的核心要求。

将问题与程序代码对应起来,找出实现问题解决方案的关键部分。

重点关注这些关键部分的逻辑和变量变化。

此外,还有一些额外的模拟算法解题技巧:

细化模拟步骤:将复杂的程序逻辑分解为更小的步骤,逐步模拟每个步骤的执行过程和结果。

记录中间状态:在模拟过程中,记录所有相关变量的中间状态,以便于跟踪和调试。

验证模拟结果:在完成模拟后,使用题目给出的测试用例或自己设计的测试用例来验证模拟结果的正确性。

注意边界条件:特别关注程序处理边界输入或特殊情况的能力,这些往往是解题的关键所在。

通过综合运用这些技巧,选手可以更加高效地利用模拟算法解决信息学竞赛初赛中的难题

3 思路分析

1 当m>0时,输出的值一定小于2n。( T )

分析

08     for (int i = 1; i <= n; ++i)
09         a[i] = b[i] = 0;
x和y都是在[1, n]的范围内的整数,说明x和y对应的数组的值赋值为0

10     for (int i = 1; i <= m; ++i) {
11         int x, y;
12         scanf("%d%d", &x, &y);
13         if (a[x] < y && b[y] < x) {
14             if (a[x] > 0)
15                 b[a[x]] = 0;
16             if (b[y] > 0)
17                 a[b[y]] = 0;
18             a[x] = y;
19             b[y] = x;
20         }
21     }
m>0 说明进入循环,并且a[x]=0 y>=1,a[y]=0 x>=1 必然存在a[x] = y;b[y] = x;
输出a数组和b数组为0的累加,如果都为0,累加和为2n,前面有不为0的,所以输出小于2n

2 执行完第27行的"++ans"时,ans —定是偶数。( F )

分析

22     int ans = 0;
23     for (int i = 1; i <= n; ++i) {
24         if (a[i] == 0)
25             ++ans;
26         if (b[i] == 0)
27             ++ans;
28     }
27行是b数组为0的累加统计,在for循环中累加,当25没累加时,27执行完就是奇数,可以尝试找出反例
n=10,m=1,x=2,y=4时
a和b数组如下图,当i=2时,25行ans没累加,此时27行ans累加后为3,不是偶数

3 a[i]和b[i]不可能同时大于0。( F )

分析

当输入的x和y相等时,a[i]和b[i]可能同时大于0
例如
n=10,m=1,x=2,y=2
a和b数组如下图,当i=2时,a[2]=2,b[2]=2

4 若程序执行到第13行时,x总是小于y,那么第15行不会被执行。( F )

分析

当x不变,y增加时可以找出反例
n=10 m=2
x=1 y=2
a[1]=2 b[2]=1
x=1 y=3
此时满足13行 a[1]>0 执行15行b[a[x]]=b[2]=0 清空b[2]对应的a的下标,后面重新赋值新的下标

5 若m个x两两不同,且m个y两两不同,则输出的值为( A )

A 2n-2m

B 2n+2

C 2n-2

D 2n

分析

m个x两两不同,且m个y两两不同,就会正常a中m个元素不为0,b中m个元素不为0
不为0的个数总共2*m个
数组a和b总共2n个元素
所以输出的ans为的元素为2*n-2*m

6 若m个x两两不同,且m个y都相等,则输出的值为( A )

A 2n-2

B 2n

C 2m

D 2n-2m

分析

如果y都相等,第1次 x ,y对a和b数组赋值后,第2次由于y不变,所以b[y]不变,所以a[b[y]]会被清0,a数组重新赋值,b[y]对应的值更新
所以每次更改后,a和b数组分别只有1个不为0的数
例如
n=10 m=2
x=2 y=1

再输入一对x y后
x=3 y=1

由此可知,无论输入多少个这样的数,最后a和b数组中只有2个不为0的数
所以ans=2n-2
posted @ 2024-08-02 17:41  new-code  阅读(9)  评论(0编辑  收藏  举报