【题目】
CSP-J 2021 入门级 第一轮 完善程序(1)
(1)(Josephus 问题)有n个人围成一个圈,依次标号0至n-1。从0号开始,依次0,1,0,1,… 交替报数,报到 1 的人会离开,直至圈中只剩下一个人。求最后剩下人的编号。
试补全模拟程序。
01 #include <iostream>
02
03 using namespace std;
04
05 const int MAXN = 1000000;
06 int F[MAXN];
07
08 int main() {
09 int n
10 cin >> n;
11 int i = 0, p = 0, c = 0;
12 while(__(1)__) {
13 if(F[i] == 0) {
14 if(__(2)__) {
15 F[i] = 1;
16 ___(3)___;
17 }
18 ___(4)___
19 }
20 ___(5)___;
21 }
22 int ans = -1;
23 for (i = 0; i < n; i++)
24 if (F[i] == 0)
25 ans = i;
26 cout << ans << endl;
27 return 0;
28 }
-
①处应填( )
A.i < n
B.c < n
C.i < n- 1
D.c < n-1 -
②处应填( )
A.i % 2 == 0
B.i % 2 == 1
C.p
D.!p -
③处应填( )
A.i++
B.i = (i + 1) % n
C.c++
D.p ^= 1 -
④处应填( )
A.i++
B.i = (i + 1) % n
C.c++
D.p ^= 1 -
⑤处应填( )
A.i++
B.i = (i + 1) % n
C.c++
D.p ^= 1
**
【题目考点】
1. 数组循环遍历
2. 位运算
【解题思路】
该问题为报数只从0报到1的约瑟夫问题,最后输出的是剩下的人。
22 int ans = -1;
23 for (i = 0; i < n; i++)
24 if (F[i] == 0)
25 ans = i;
26 cout << ans << endl;
通过看最后一段可知,遍历F数组,找到其中值为0的元素的下标保存在ans变量,而后输出ans。
因此F数组的含义为:F[i]
为0表示第i个人还在,F[i]
为1表示第i个人已经离开。
11 int i = 0, p = 0, c = 0;
12 while(__(1)__) {
13 if(F[i] == 0) {
14 if(__(2)__) {
15 F[i] = 1;
16 ___(3)___;
17 }
18 ___(4)___
19 }
20 ___(5)___;
21 }
接下来看核心的一段,都是空,基本相当于需要我们自己写。而选择题的选项其实也能给我们提供提示。
第(1)空要填的是while循环进行的条件,先向下看。
如果F[i]为0,也就是i还在,那么接下来就该考虑第i人是否数到1,如果数到1就该离开。
所以第(2)空应该填的意义为:第i人是否数到1。
满足该条件,F[i]设为1,也就是第i人离开。而后做的事情填在第(3)空。
每当一人离开,应该做一次计数,离开的人数达到n-1个就应该结束了。结合第(1)空的选项,可以看出c表示离开的人数。第(1)空应该填c < n-1
,选D。第(3)空应该填c++
,选C。
无论第i人是否数到1,都要做的事情填在第(4)空。
判断当前数1还是数0的变量应该是p(就剩下p变量没有用了),p为1表示应该数1,p为0表示应该数0。因此第(2)空应该填p为1,作为判断条件,p为1、p为真、或只写p的效果是一样的。所以选C。第(4)空为p的变化,p应该是如果是0就变1,如果是1就变0,p ^= 1
操作可以实现这一点,选D。
无论F[i]是否为0,都做的事情填在第(5)空。
i是F数组的下标,应该对F数组进行循环遍历,直到只有一个元素还在,i遍历到n-1时,i的下一个位置是0,因此第(5)空应该填i的变化方式,即i = (i+1)%n
,选B。
【答案】
- D
- C
- C
- D
- B