一群猴子要选新猴王。新猴王的选择方法是:让N只候选猴子围成一圈,从某位置起顺序编号为1~N号。从第1号开始报数,每轮从1报到3,凡报到3的猴子即退出圈子,接着又从紧邻的下一只猴子开始同样的报数。如此不断循环,最后剩下的一只猴子就选为猴王。请问是原来第几号猴子当选猴王?
输入格式:
输入在一行中给一个正整数 N(≤ 1000)。
输出格式:
在一行中输出当选猴王的编号。
输入样例:
11
输出样例:
7
解题思路:
- 第一种方法(算法一):
给每个猴子初始设为 0,退出时就置为 1,最后检查数组中的数字,是 0 就输出。难点在于让判断循环进行以及循环出口。- 让判断循环进行:当 i == N 时,将其置 0,这样就能继续循环。
- 循环出口:直到退出的猴子数等于 N-1,就是还剩一只猴子就退出。
- 第二种方法(算法二):
增加一个数组,每次将数组筛选,将剩下的猴子放进新的数组里。直到数组里就剩 2 只猴子(与筛选算法有关)。在文章的最后会解释算法二中的一点小细节。
另外,要注意数组的初始化
scanf("%d", N);
int a[N]={0};
初始化的时候 N 的值需要已知。初始化是在编译时完成。所以 N 尚未输入。这样就会产生错误。解决方法是用一个 for 循环完成初始化。
解题代码:
算法一
#include
int main ()
{
int N, i;
scanf("%d", &N);
int a[N+1]; //舍弃 a[0],方便给猴子编号
for (i=1; i
算法二
#include
int main ()
{
int N, i;
scanf("%d", &N);
int a[N+1]; // 舍弃 a[0],方便给猴子编号
for (i=1; i 2) {
for (i=1; i<=N; i++) {
if (i == 1) {
switch (N % 3) {
case 0: count = 1; break;
case 1: count = 2; break;
case 2: count = 3; break;
} // 算法的下方会给出讲解
}
if (i%3 != 0 && i<=N/3*3) {
b[count++] = a[i];
}
if (i%3 != 0 && i>N/3*3) {
switch (N % 3) {
case 0: break;
case 1: b[1] = a[i]; break;
case 2:
if (i == N) {
b[1] = a[i-1];
b[2] = a[i];
}
break;
}
}
}
N = count - 1;
for (i=1; i<=count-1; i++) {
a[i] = b[i];
} // 将新的数组 b 赋给原数组 a
}
if (N == 1) {
printf("1\n");
} else {
printf("%d\n", a[2]);
}
return 0;
}
算法二中的一点细节:
if (i == 1) {
switch (N % 3) {
case 0: count = 1; break;
case 1: count = 2; break;
case 2: count = 3; break;
} // 算法的下方会给出讲解
}
在形成新的数组之后,要从第一个开始访问,当 N 不同的时候,第一个的情况会有所不同,所以有了上面的处理。
比如 N = 3 时,
a[i] 1 2 3 猴子编号 1 2 3↓
b[count] 1 2 猴子编号 1 2 当 N 恰为 3 的倍数时,下一次从猴子 1 号开始数。所以 switch 那里将 b 的初始指针设为了 1。
而当 N = 4 时,
a[i] 1 2 3 4 猴子编号 1 2 34 ↓
b[count] 1 2 3 猴子编号 4 1 2 当 N 为 4 的时候,下一次从猴子 4 号开始数,所以 switch 那里将 b 的初始指针设为了 2。把 b[1] 的位置留给 4 号猴子。
而当 N = 5 时,
a[i] 1 2 3 4 5 猴子编号 1 2 34 5 ↓
b[count] 1 2 3 4 猴子编号 4 5 1 2 当 N 为 5 的时候,下一次从猴子 4 号开始数,所以 switch 那里将 b 的初始指针设为了 3。把 b[1] 的位置留给 4 号猴子,b[2] 的位置留给 5 号猴子。