一群猴子要选新猴王。新猴王的选择方法是:让N只候选猴子围成一圈,从某位置起顺序编号为1~N号。从第1号开始报数,每轮从1报到3,凡报到3的猴子即退出圈子,接着又从紧邻的下一只猴子开始同样的报数。如此不断循环,最后剩下的一只猴子就选为猴王。请问是原来第几号猴子当选猴王?
输入格式:
输入在一行中给一个正整数N(≤1000)。
输出格式:
在一行中输出当选猴王的编号。
输入样例:
11
输出样例:
7
这道题的考点就是约瑟夫环,看到了一组巨简洁的代码
#include<stdio.h>
int main(void)
{
//表达每数到3就退一个
int N = 0;
int sum = 0;
scanf("%d", &N);
for(int i = 2; i <= N; i++)
sum = (sum + 3) % i;
printf("%d", sum + 1);
return 0;
}
约瑟夫环问题,这是一个很经典算法,处理的关键是:伪链表
问题描述:N个人围成一圈,从第一个人开始报数,报到m的人出圈,剩下的人继续从1开始报数,报到m的人出圈;如此往复,直到所有人出圈。(模拟此过程,输出出圈的人的序号)
void joseph(int count, int doom) {
int alive = count; //幸存人数
int number = 0; //计数,当number==doom时,淘汰这个人
int index = 0; //下标,为总人数-1
int *circle = NULL; //根据需求设为循环数组,存储每个人
//用calloc()函数申请得到的空间,自动初始化每个元素为0
//所以,0表示在这个人在约瑟夫环内,1表示这个人出圈,即“淘汰”
circle = (int *) calloc(sizeof(int), count);
//只要幸存人数大于0,则一直进行循环
while(alive > 0) {
number += 1- circle[index]; //每轮到一个人报数,不管是"0"还是"1"都进行计数
if(number == doom) { //当number==doom时,就要淘汰当前这个人
/*
淘汰一个人需要做四步操作:
1、输出这个人的位置
2、把这个人的状态从在圈内"0"改为不在圈内"1"
3、幸存人数alive--
4、 计数器number归零
*/
alive == 1 ? printf("%d", index+1) : printf("%d,", index+1);
circle[index] = 1;
alive--;
number = 0;
}
//与总人数count取余,则可以使index在0~count-1之间 一直循环,达到循环数组的目的
index = (index +1) % count;
}
printf("\n");
free(circle); //结束后一定要释放circle所申请的空间