编号为 1,2,3,…,n 的 n 个人围坐一圈,任选一个正整数 m 作为报数上限值,从第一个人开始按顺时针方向报数,报数到 m 时停止,报数为 m 的人出列。从出列人的顺时针方向的下一个人开始又从 1 重新报数,如此下去,直到所有人都全部出列为止。
思路:采用标号法。
使每一个人的初始生命值为1,当一个人报号到n的时候,将他的生命值置为零,下次计数的时候就跳过它,直到留下一个人。
代码如下:
#include<stdio.h>
#include<assert.h>
#include<malloc.h>
int josef(int* arr, int m,int n)
{
assert(arr != nullptr);
if (arr == nullptr)
{
return -1;
}
//计数
int count = 0;
//幸存人数
int survivor = n;
while (survivor > 1)
{
for (int i = 0; i < n; i++)
{
if (*(arr + i) == 1)
{
count++;
if (count == m)
{
*(arr + i) = 0;
count = 0;
survivor--;
}
}
}
}
for (int i = 0; i < n; i++)
{
if (*(arr + i) == 1)
{
return i;
}
}
}
int main()
{
int n,m;
printf("请输入参与人数n\n");
scanf_s("%d" , &n);
printf("请输入上限m\n");
scanf_s("%d", &m);
int* arr = (int*)malloc(n * sizeof(int));
for (int i = 0; i < n; i++)
{
*(arr + i) = 1;
}
int result = josef(arr, m, n);
printf("%d",result);
}
难点如下:
①变量比较多,需要明白各变量代表的意义,以及在各种情况下值的改变方式。
如当计数变量count达到报数上限m时,幸存人数survivor要减一,这个人的生命值要减一,计数变量要重新计数。
②for,while,if的循环套用,容易混淆。要明确整个循环的循环条件和退出条件。
如这个题目的退出条件就是幸存人数达到1,否则就一直循环计数,淘汰。所以用while比较好。