[洛谷]P1996 约瑟夫问题

一、问题描述

[洛谷]P1996 约瑟夫问题

题目描述

n n n 个人围成一圈,从第一个人开始报数,数到 m m m 的人出列,再由下一个人重新从 1 1 1 开始报数,数到 m m m 的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。

输入格式

输入两个整数 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 1m,n100

二、思路分析

1、算法标签:

这道题考察的是数据结构中的:环形链表、队列

2、算法分析:

这道题的关键其实在于如何将进行循环访问

我们最容易想到的其实就是利用数组模拟一个环形链表。这样的话,每当我们遍历到尾部节点的时候,就会自动跳到头节点。

当然我们还可以使用一个队列。每次报数的时候,我们就让队头出队。如果这个人不是要出局的人,我们就让这个人再次入队,等待下一次报数。如果这个人是要出局的人,那么这个人就不需要再入队了,直接淘汰即可。

三、代码实现

1、环形链表

#include<iostream>
using namespace std;
const int N=110;
int e[N],ne[N],idx,h=-1;
int n,m;
void add(int x)
{
    e[idx]=x,ne[idx]=h,h=idx++;
}
void del(int x)
{
    ne[x]=ne[ne[x]];
}
int main()
{
    cin>>n>>m;
    for(int i=n;i>=1;i--)
        add(i);
    //构造环形队列,让队尾指向队头
    ne[0]=h;
    int k=0;
    int prev=0;
    int num=0;
    for(int i=h;num!=n;i=ne[i])
    {
        k++;
        if(k==m)
        {
            del(prev);
            num++;
            cout<<e[i]<<" ";
            k=0;
        }
        prev=i;
        
    }
    return 0;
}

由于我们是头插的,所以我们最开始插入的那个节点最终会编程尾部节点,即我们 i d x = 0 idx=0 idx=0时对应的那个节点就是我们最终的尾部节点。

我们想要构造一个环形链表的话,就需要让尾部节点记录头指针。
所以才出现了我们的这一行代码:ne[0]=h;

在这里插入图片描述

2、队列

#include<iostream>
#include<queue>
using namespace std;
queue<int>q;
int n,m;
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        q.push(i);
    int k=0;
    while(!q.empty())
    {
        
        int t=q.front();
        k++;
        q.pop();
        if(k!=m)
        {
            q.push(t);
        }
        else
        {
            k=0;
            cout<<t<<" ";
        }
    }
    return 0;
}

在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值