题目描述:有n人围成一圈,顺序排号。从第1个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来的第几号的那位。 ####相关知识(略)
时间: 2023-12-23 19:18:02 浏览: 95
这是一个经典的约瑟夫问题(Josephus problem),可以用递归或数学公式来解决。
方法1:递归
假设 f(n,m) 表示 n 个人报数到 m 时最后剩下的人的编号,则有:
f(n,m) = (f(n-1,m)+m) % n
其中 % 表示取模运算。这个公式表示,当 n 个人报数到 m 时,第一个被淘汰的人的编号是 (m-1)%n,剩下的 n-1 个人组成一个新的序列,从被淘汰的人的下一个人开始报数,报数到 m-1 时相当于从新的序列中淘汰了一个人。因此,最后剩下的人的编号就是在新的序列中的编号加上被淘汰的人的编号,取模后对 n 取余。
当 n=1 时,显然剩下的是第一个人,即 f(1,m)=0。
方法2:数学公式
当 m=2 时,这个问题有一个很简单的数学解法,最后剩下的人的编号是 2*(n-2^k)+1,其中 k 是满足 2^k <= n < 2^(k+1) 的最大整数。
当 m>2 时,这个问题的数学解法比较复杂,可以参考维基百科的介绍:https://en.wikipedia.org/wiki/Josephus_problem#k=2
相关问题
用C语言写题目描述:有n人围成一圈,顺序排号。从第1个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来的第几号的那位
```
#include <stdio.h>
int main() {
int n, i, count = 0, index = 0;
printf("请输入总人数:");
scanf("%d", &n);
int arr[n];
for (i = 0; i < n; i++) {
arr[i] = i + 1;
}
while (count < n - 1) {
if (arr[index] != 0) {
count++;
if (count % 3 == 0) {
arr[index] = 0;
}
}
index++;
if (index == n) {
index = 0;
}
}
for (i = 0; i < n; i++) {
if (arr[i] != 0) {
printf("最后留下的是原来的第%d号\n", arr[i]);
break;
}
}
return 0;
}
```
用C语言写题目描述:有n人围成一圈,顺序排号。从第1个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来的第几号的那位。 ####相关知识(略)
#include <stdio.h>
int main() {
int n, i, j, k, left, count, number[100];
printf("请输入总人数n:");
scanf("%d", &n);
// 初始化编号
for (i = 0; i < n; i++) {
number[i] = i + 1;
}
left = n;
count = 0;
i = 0;
// 开始报数
while (left > 1) {
if (number[i] != 0) {
count++;
}
if (count == 3) {
number[i] = 0;
count = 0;
left--;
}
i++;
if (i == n) {
i = 0;
}
}
// 输出最后一个留下来的人的编号
for (i = 0; i < n; i++) {
if (number[i] != 0) {
printf("最后留下来的是原来的第%d号的那位。\n", number[i]);
break;
}
}
return 0;
}
阅读全文