P1996 约瑟夫问题

约瑟夫问题解法

解法一:STL队列实现

#include <iostream>
#include <queue>
using namespace std;

int main() {
    int n, m;
    cin >> n >> m;
    
    queue<int> q;
    // 初始化队列,将所有人按顺序加入队列
    for (int i = 1; i <= n; i++) {
        q.push(i);
    }
    
    while (q.size()) {
        // 将前m-1个人从队首取出并放到队尾
        for (int i = 1; i < m; i++) {
            q.push(q.front());
            q.pop();
        }
        // 第m个人出列
        cout << q.front() << " ";
        q.pop();
    }
    
    return 0;
}

思路解析:

  1. 使用STL的queue来模拟环形结构

  2. 所有人按顺序入队

  3. 每次处理时,将前m-1个人从队首移动到队尾

  4. 第m个人就是当前队首元素,输出并出队

  5. 重复上述过程直到队列为空

解法二:数组模拟队列

#include<bits/stdc++.h>  // 包含所有标准库头文件
using namespace std;

const int N = 1e2 + 10;  // 定义常量N为110,作为队列大小
int q[N * N];             // 定义队列数组,大小足够大
int head, tail;           // 定义队首和队尾指针
int n, m;                 // 定义总人数n和报数m

int main() {
    cin >> n >> m;        // 输入总人数n和报数m
    
    // 初始化队列,将所有人按顺序加入队列
    for(int i = 1; i <= n; i++) 
        q[tail++] = i;    // 将i放入队尾,tail指针后移
    
    int id = 1;            // 初始化报数计数器
    
    while(head < tail)     // 当队列不为空时循环
    {
        if(id % m == 0) {  // 如果当前报数是m的倍数
            cout << q[head] << " ";  // 输出当前队首的人(出圈)
            head++;                  // 队首指针后移,相当于出队
        }
        if(id % m != 0) {  // 如果当前报数不是m的倍数
            q[tail++] = q[head];     // 将队首的人移到队尾
            head++;                  // 队首指针后移
        }
        id++;             // 报数计数器增加
    }
    
    return 0;
}

代码逻辑解析:

  1. 队列初始化:将1到n的数字依次放入队列中

  2. 循环处理:

    • 使用id计数器记录当前报数

    • idm的倍数时,当前队首的人出圈(输出并移出队列)

    • id不是m的倍数时,将当前队首的人移到队尾

  3. 循环条件:当队首指针head小于队尾指针tail时,表示队列中还有人

注意事项:

  • 队列大小N*N设置得足够大,确保不会溢出

  • head指针始终指向当前队首元素

  • tail指针始终指向队尾下一个可插入位置

  • 每次操作后id都会自增,保证报数连续

posted @ 2025-05-27 16:20  CRt0729  阅读(27)  评论(0)    收藏  举报