约瑟夫问题
题目描述
n n n 个人围成一圈,从第一个人开始报数,数到 m m m 的人出列,再由下一个人重新从 1 1 1 开始报数,数到 m m m 的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。
注意:本题和《深入浅出-基础篇》上例题的表述稍有不同。书上表述是给出淘汰 n − 1 n-1 n−1 名小朋友,而该题是全部出圈。
输入格式
输入两个整数 n , m n,m n,m。
输出格式
输出一行 n n n 个整数,按顺序输出每个出圈人的编号。
样例 #1
样例输入 #1
10 3
样例输出 #1
3 6 9 2 7 1 8 5 10 4
提示
1 ≤ m , n ≤ 100 1 \le m, n \le 100 1≤m,n≤100
代码
1. 动态链表
#include <iostream>
using std::cin, std::cout;
struct node {
int data; // 节点的值
node * next; // 指向下一个节点
};
int main() {
int n, m; // n为人数,m为出列的人报的数
cin >> n >> m;
node *head, // head指向链表的头部
*pnew, // pnew用于创建新的节点
*current, // current指向当前的节点
*prev; // prev指向当前节点的上一个节点
// 初始化链表头
head = new node; head->data = 1; head->next = NULL;
current = head; // 让当前节点指向链表头(同时也是尾节点)
for (int i = 2; i <= n; i++) { // 初始化链表
// 初始化新节点pnew
pnew = new node; pnew->data = i; pnew->next = NULL;
// 把pnew载入链表,并且更新当前指针指向新节点(尾节点)
current->next = pnew; current = pnew;
}
current->next = head; // 构建循环链表
current = head; // 让当前节点指向链表头(从头开始遍历链表)
while (n-- > 1) { // 直到链表节点只剩一个为止
for (int i = 1; i < m; i++) { // 找到第m个人
prev = current; // prev指向current更新前的节点
current = current->next; // 更新current
}
cout << current->data << " "; // 输出第m个节点和空格
prev->next = current->next; // 跳过当前第m个节点
delete current; // 删除第m个节点
current = prev->next; // 开始新的一轮报数
}
cout << current->data; // 输出最后一个节点
delete current; // 删除最后一个节点
return 0;
}
2. 静态链表(使用结构体数组实现)
#include <iostream>
using std::cin, std::cout;
const int ListSize = 105; // 链表的长度
struct node {
int id; // 节点的编号
int nextid; // 指向下一个节点的索引
} list[ListSize];
int main() {
int n, m; // n为人数,m为出列的人报的数
cin >> n >> m;
for (int i = 1; i <= n; i++) { // 初始化链表
list[i].id = i; // 节点的编号为i
list[i].nextid = i + 1; // 下一个节点的索引为i + 1
}
list[n].nextid = 1; // 构成循环链表
// current是当前节点的编号,prev是上一个节点的编号
int current = 1, prev = 1;
while (n-- > 1) { // 直到链表节点只剩一个为止
for (int i = 1; i < m; i++) { // 找到第m个人
prev = current; // prev保存上一个节点的编号
current = list[current].nextid; // 更新current到下一个节点
}
cout << list[current].id << " "; // 输出编号和空格
list[prev].nextid = list[current].nextid; // 跳过当前节点
current = list[prev].nextid; // 开始新一轮报数
}
cout << list[current].id; // 输出最后一个节点的值
return 0;
}
3. 静态链表(用一维数组实现)
#include <iostream>
using std::cin, std::cout;
const int ListSize = 105;
int list[ListSize]; // 链表的长度
int main() {
int n, m; // n为人数,m为出列的人报的数
cin >> n >> m;
for (int i = 1; i <= n - 1; i++) {
list[i] = i + 1;
}
list[n] = 1; // 构成循环链表
// current是当前节点的编号,prev是上一个节点的编号
int current = 1, prev = 1;
while (n-- > 1) { // 直到链表节点只剩一个为止
for (int i = 1; i < m; i++) { // 找到第m个人
prev = current; // prev保存上一个节点的编号
current = list[current]; // 更新current到下一个节点
}
cout << current << " "; // 输出编号和空格
list[prev] = list[current]; // 跳过当前节点
current = list[prev]; // 开始新一轮报数
}
cout << current; // 输出最后一个节点的值
return 0;
}