[题目描述]
一群猴子要选新猴王。新猴王的选择方法是:让N只候选猴子围成一圈,从某位置起顺序编号为1~N号。从第1号开始报数,每轮从1报到3,凡报到3的猴子即退出圈子,接着又从紧邻的下一只猴子开始同样的报数。如此不断循环,最后剩下的一只猴子就选为猴王。请问是原来第几号猴子当选猴王?
[输入格式]
输入在一行中给一个正整数N(≤1000)。
[输出格式]
在一行中输出当选猴王的编号。
输入样例:
11
输出样例:
7
解题思路 :
对于猴子选大王这道题,每次从1数到3,喊到数字3的猴子退出圈子,直到最后只有一只猴子为止。我的初步想法是用一个数组来解决问题,由于数组是从0开始,而我们这道题的猴子是从1编号,所以我在数组下标为0的位置放置0,这样数组下标为1的位置放置1,以此类推。可以用一个变量cnt来表示数组中元素为0的个数,当cnt小于猴子的总数时一直进行如下循环:使用变量i记录数组下标,我们希望i所对应的元素非0,同时注意i的值不能大于猴子总数;使用变量j记录从1数到3,当j大于3时置j为1,当j为3时,将数组下标为i的元素置为0,同时cnt加1。最后输出数组中的非0元素即为我们想要的结果。
还可以使用约瑟夫环一种数学方法,不过我还没有搞明白o(╥﹏╥)o
C语言代码如下:
#include <stdio.h>
int main(void){
int n,i,a[1000],cnt,j,k;scanf("%d",&n);
for(i=0;i<=n;i++){a[i]=i;}
cnt=1;i=0;j=1;while(a[i]==0){i++;if(i>n)i=0;}
while(cnt<n){
if(j==3){a[i]=0;cnt++;}
j++;if(j>3)j=1;
i++;if(i>n)i=0;
while(a[i]==0){i++;if(i>n)i=0;}}
for(k=0;k<=n;k++){if(a[k])printf("%d",a[k]);}
return 0;}
【也可以这样写】最近又遇到了类似的题目,重新写了一下。
# include <stdio.h>
int main()
{
int n;
scanf("%d", &n); // 输入猴子的数量
int m = 3; // 变量m记录报到哪个数要退出圈子
int s = n; // 变量s记录当前在圈内的猴子数
int a[1005] = {0}; // 数组a记录这n个猴子是否在圈内,初始值全为0,表示n个猴子全部在圈内,出圈后应修改元素为1
int k = 0, p = 0; // 变量k记录当前报数是多少,变量p记录当报到最后一个猴子时,反过来从前面的哪个位置开始报数
while (s) { // 当圈内有猴子时进行循环
while (a[p] != 0) { // 找到本次报数从第几个猴子开始报数
++p;
}
for (int i = p; i < n; ++i) { // 遍历数组a
if (!a[i]) { // 如果第i+1个猴子在圈内,
++k; // 报数加1
if (k == m) { // 恰好报到m
if (s == 1) {
printf("%d", i + 1); // 输出猴王的编号
}
a[i] = 1; // 修改对应元素为1
--s; // 圈内的猴子数要相应减1
k = 0; // 报数归零,从0开始
}
}
}
}
return 0;
}
也可以这样写。
#include <stdio.h>
#define N 80
int main(void)
{
int n;
printf("Enter n:");
scanf("%d", &n);
int a[N] = {0};
int cnt = n;
int k = 0, i = 0;
while (1) {
if (a[i] == 0) {
k++;
if (k == 3) {
a[i] = !a[i];
cnt--;
if (cnt == 1) {
for (int p=0; p<n; p++) {
if (a[p] == 0) {
printf("Last No is %d", p+1);
}
}
break;
}
k = 0;
}
}
i++;
if (i == n) {
i = 0;
}
}
return 0;
}