PTA 约瑟夫环

发布时间 2023-11-29 21:06:44作者: 吧拉吧拉吧

约瑟夫环

作者 吴锦桥  单位 西北农林科技大学

有N个人围成一圈(编号为1~N),从第1号开始进行1、2、3报数,凡报3者就退出,下一个人又从1开始报数……直到最后只剩下一个人时为止。请问此人原来的编号是多少?

输入格式:

在一行中给出1个不超过100的正整数N。

输出格式:

在一行中输出最后剩下那个人的编号。

输入样例:

10

输出样例:

4

分析:

  • 方法一:公式法。该题目最后能推导出一个递归公式:f(N,M)=(f(N−1,M)+M)%N;其中f(N,M)表示,N个人报数,每报到M时杀掉那个人,最终胜利者的编号;f(N−1,M)表示,N-1个人报数,每报到M时杀掉那个人,最终胜利者的编号
#include<iostream>
#include<set>
using namespace std;


int main(){
    int n,f=0;
    cin>>n;
    for (int i = 1; i <= n; i++) 
        f = (f + 3) % i;
    cout << f + 1 << endl;
}
  • 方法二:首先使用一个队列来模拟。然后使用一个计数器count来记录当前报数的次数。每次循环中,如果count等于3,说明当前这个人需要退出,我们就从队列中弹出他。否则,我们将队首的人移到队尾,并弹出他,模拟他报数后移动到下一个人的过程。最后,当队列中只剩下一个人时,他就是最后的胜利者,输出他的编号
#include <iostream>  
#include <queue>  
using namespace std;

int main() {  
    int n;
    cin >> n;
    queue<int> q;
    for (int i = 1; i <= n; i++) {
        q.push(i);
    }
    int count = 0;
    while (q.size() > 1) {
        count++;
        if (count == 3) {
            q.pop();
            count = 0;
        } else {
            q.push(q.front());
            q.pop();
        }
    }
    cout << q.front() << endl;
    return 0;
}