题目描述 n n 个人围成一圈,编号为 1 ∼ n 1∼n,从第一个人开始报数,从 1 1 开始,数到 m m 的人出列,再由下一个人重新从 1 1 开始报数,数到 m m 的人再出列,依次类推,直到所有的人都出列,请依次输出每次出列人的编号。 输入描述 输入两个整数 n , m n,m。 输出描述 输出一行 n n 个整数,按出列顺序输出每个出列人的编号。 样例1 输入 10 3 输出 3 6 9 2 7 1 8 5 10 4 提示 对于 50 % 50% 的数据, m , n ≤ 50 m,n≤50。 对于 100 % 100% 的数据, m , n ≤ 1000 m,n≤1000。c++
时间: 2025-03-08 09:03:25 浏览: 85
### 解决约瑟夫环问题的 C++ 实现
为了实现约瑟夫环问题,在 C++ 中可以采用多种数据结构来模拟这个过程。一种常见的方式是利用链表或者向量(`std::vector`),因为这些容器支持动态调整大小以及方便地移除元素。
以下是基于 `std::list<int>` 的解决方案:
```cpp
#include <iostream>
#include <list>
using namespace std;
void josephusProblem(int n, int m) {
list<int> people;
// 初始化列表,代表编号为1至n的人
for (int i = 1; i <= n; ++i){
people.push_back(i);
}
auto it = people.begin(); // 创建迭代器指向第一个节点
while (!people.empty()) {
// 移动到第m个人的位置并处理越界情况
for (int count = 1; count < m; ++count) {
if (++it == people.end())
it = people.begin();
}
cout << *it << ' '; // 输出即将被删除的人
// 删除当前指针所指向的人,并更新迭代器
it = people.erase(it);
// 如果列表不为空,则移动到下一个位置
if (!people.empty() && it == people.end()){
it = people.begin();
}
}
}
```
上述代码通过创建一个包含所有人编号的双向链表来进行模拟[^1]。每当到达指定间隔数目的时候就执行一次删除操作,并打印出该人的编号;当某一轮结束之后继续从未被淘汰的第一个成员处重新计数直至所有人都被淘汰为止。
另一种更高效的解法则是直接计算每一位幸存者的索引而不需要实际构建和修改任何集合对象。这种方法依赖于递推公式:
\[ f(n,m)=(f(n−1,m)+m)\%n \]
其中 \(f(n,m)\) 表达的是在只有\(n\)名参与者的情况下最后剩下的一位选手所在初始位置。此算法的时间复杂度仅为O(N),非常高效[^2]。
#### 使用数组存储结果版本
考虑到题目要求输出具体的淘汰顺序而非仅最后一个存活者的信息,这里提供另一个使用静态数组保存每轮被淘汰人员的方法:
```cpp
#include <iostream>
#define MAXN 10005
using namespace std;
int main(){
int n, m, s=0;
cin >> n >> m;
bool vis[MAXN];
memset(vis,false,sizeof(vis));
for(int i=1;i<=n;++i)
vis[i]=true;
for(int cnt=n,i=m;;cnt--){
while(!vis[(s+i-1)%n+1])//跳过已经出局的人
s=(s+n-1)%n;
int out=((s+i-1)%n+1);
cout<<out<<" ";
if(--cnt==0) break;
vis[out]=false;
}
return 0;
}
```
这段程序同样实现了完整的约瑟夫环逻辑,不过它采用了布尔型数组标记哪些人已经被淘汰了,从而可以在遍历时轻松越过他们而不必改变原始的数据结构[^3]
阅读全文
相关推荐
















