题目描述 n个人排成一圈,按顺时针方向依次编号1,2,3…n。从编号为1的人开始顺时针"一二三...."报数,报到m的人退出圈子。这样不断循环下去,圈子里的人将不断减少。最终一定会剩下一个人。试问最后剩下的人的编号。 本题的数据规模更具有挑战性,尝试更通用且高效的算法。 输入 不超过1000组数据。 每组数据一行,每行两个正整数,代表人数n (1 <= n < 231)和m(1<=m<=1000)。 输出 每组输入数据输出一行, 仅包含一个整数,代表最后剩下的人的编号。 样例输入 Copy 7 2 2 2 样例输出 Copy 7 1
时间: 2024-04-21 07:28:28 浏览: 20
这道题可以使用数学方法解决,不需要模拟整个过程。具体来说,我们可以从最后一轮游戏开始,设剩下的人的编号为f(n,m)。显然,在最后一轮游戏中,第一个出圈的人的编号是(m-1)%n+1,记为k。那么,剩下的n-1个人中,下一轮游戏编号为k+1,k+2,...,n,1,2,...k-2,k-1,相当于把原来的编号整体向左移动了k个位置。因此,剩下的人的编号是f(n-1,m),但是这个编号是相对于移动后的编号的,要转换为相对于原来的编号,需要加上k。因此,f(n,m)=(f(n-1,m)+k)%n。
最终,当n=1时,剩下的人的编号就是1。因此,我们可以使用递归的方法来计算f(n,m)。时间复杂度为O(n),可以通过本题。下面是AC代码:
相关问题
n个人排成一圈,按顺时针方向依次编号1,2,3…n。从编号为1的人开始顺时针"一二"报数,报到2的人退出圈子。这样不断循环下去,圈子里的人将不断减少。最终一定会剩下一个人。试问最后剩下的人的编号。
这个问题可以使用约瑟夫问题的思路来解决。设最后剩下的人的编号为 f(n,m),表示有 n 个人时,按照题目的规则报数到 m 的人最后剩下的编号。
当 n=1 时,剩下的人的编号为1,即 f(1,m)=1。
当 n>1 时,第一轮报数后,编号为 m 的人出圈,剩下了 n-1 个人,假设剩下的人继续从编号为 m+1 开始报数,那么他们的编号会变成 1,2,...,n-m。因此,剩下的人最后的编号就是 f(n-1,m)。但是,这个编号是相对于剩下的 n-1 个人来说的,如果把它转化为相对于原来的 n 个人的编号,就需要加上 m,即 f(n,m)=f(n-1,m)+m。但是,由于每次报数后都是从下一个人开始报数,因此,编号也要相应地向前移动 m 个位置,即 f(n,m)=(f(n-1,m)+m)%n,其中 "%" 表示取模运算。
按照上述递推公式,可以求出最后剩下的人的编号。
n个人排成一圈,按顺时针方向依次编号1,2,3…n。从编号为1的人开始顺时针一二报数,报到2的人退出圈子。这样不断循环下去,圈子里的人将不断减少。最终一定会剩下一个人。试问最后剩下的人的编号。 要求程序模
以下是使用链表模拟循环链表的解法,时间复杂度为O(nm):
```c
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int num; // 编号
struct node *next; // 下一个节点
} Node;
int main() {
int n; // n个人
int m = 2; // 报数到m的人出圈
scanf("%d", &n);
Node *head = (Node*)malloc(sizeof(Node)); // 创建循环链表
head->num = 1;
Node *p = head;
for (int i = 2; i <= n; i++) {
Node *new_node = (Node*)malloc(sizeof(Node));
new_node->num = i;
p->next = new_node;
p = new_node;
}
p->next = head; // 链表首尾相连
p = head;
while (p->next != p) { // 只要还有超过1个人在圈子里就继续报数
for (int i = 1; i < m; i++) { // 报数到m的人出圈
p = p->next;
}
Node *q = p->next;
p->next = q->next;
printf("%d ", q->num); // 输出出圈的人的编号
free(q); // 释放出圈的人的内存空间
}
printf("%d", p->num); // 剩下最后一个人的编号
free(p); // 释放最后一个人的内存空间
return 0;
}
```
上述代码中,我们使用一个循环链表来模拟圆桌上的人。首先创建一个包含n个节点的循环链表,每个节点代表一个人,从编号1开始顺时针排列。然后按照题目要求进行报数和出圈,直到圆桌上只剩下一个人。最后输出这个人的编号,并释放所有节点的内存空间。