作者 吴锦桥
单位 西北农林科技大学
有N个人围成一圈(编号为1~N),从第1号开始进行1、2、3报数,凡报3者就退出,下一个人又从1开始报数……直到最后只剩下一个人时为止。请问此人原来的编号是多少?
输入格式:
在一行中给出1个不超过100的正整数N。
输出格式:
在一行中输出最后剩下那个人的编号。
输入样例:
10
输出样例:
4
代码长度限制 16 KB
时间限制 400 ms
内存限制 64MB
该题可以模拟报数过程的行为逻辑,来编写代码。
例如下面的代码:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int i, j, n, count = 1, a[1000] = { 0 };
scanf("%d",&n);
i =j= 0;
while ((j++) < n) {
while (1) {
i++;
if (i > n) i = 1;
while (a[i] != 0) {
i++;
if (i > n) i = 1;
}if (count == 3) {
a[i] = 1;
count = 1;
break;
}
count++;
}
}
printf("%d", i);
return 0;
}
但也可以使用数学知识来解决,是有关模的运算的知识
这类题还被称为约瑟夫环问题
设 n 个人的问题的解为 f(n),即 n 个人中最后一个被移除的人的编号。我们可以得到递推关系:
f(n)=(f(n−1)+m) mod n
其中,m 是数的步长,表示每次数多少个人。这个递推关系的意义是,如果我们知道 n-1 个人的问题的解 f(n-1),那么在 n 个人的情况下,就是在 n-1 个人的基础上再数 m 个人,并且取余数(因为是环形)。
初始情况是 f(1) = 0,因为只有一个人的时候,他就是最后一个被移除的人。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int n, s = 0, i;
scanf("%d", &n);
for (i = 2; i <= n; i++)
s = (s + 3) % i;
printf("%d", s + 1);
return 0;
}
直接循环迭代,求出来的结果再+1。因为是在从0开始的环计算的,而题目的序号是从1开始的