luoguP1996 约瑟夫问题

 P1996 约瑟夫问题

    • 2.5K通过
    • 4.7K提交
  • 题目提供者 Timothy
  • 标签 洛谷原创 云端
  • 难度 普及-
  • 时空限制 1s / 128MB

题目背景

约瑟夫是一个无聊的人!!!

题目描述

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

输入输出格式

输入格式:

n m

输出格式:

出圈的编号

输入输出样例

输入样例#1:
10 3
输出样例#1:
3 6 9 2 7 1 8 5 10 4

说明

你猜,你猜,你猜猜猜......

猜不着吧,我也不告诉你!!!

思路:
    首先这道题暴力可以过....(数据水死了qwq)
       接着,本题我们可以用数组建立标志位(链表)等方法求解,但如果用上数据结构中循环链的思想,则更贴切题意,解题效率更高。n人围成一圈,把一人看成一个结点,n人之间的关系采用链接方式,即每一结点有一个前继结点和一个后继结点,每一个结点有一个指针指向下一个结点,最后一个结点指针指向第一个结点。这就是单循环链的数据结构。当m人出列时,将m结点的前继结点指针指向m结点的后继结点指针,即把m结点驱出循环链。
  1、建立循环链表。
         当用数组实现本题链式结构时,数组q[i]作为"指针"变量来使用,q[i]存放下一个结点的位置。设立指针j指向当前结点,则移动结点过程为j=q[j],当数到m时,m结点出链,则q[j]=q[q[j]]。 当直接用链来实现时,则比较直观,每个结点有两个域:一个数值域,一个指针域,当数到m时,m出链,将m结点的前继结点指针指向其后继结点;
  2、设立指针,指向当前结点,设立计数器,计数数到多少人;
  3、沿链移动指针,每移动一个结点,计数器值加1,当计数器值为m时,  则m结点出链,计数器值置为1。
  4、重复3,直到n个结点均出链为止。
上代码:
1)
///暴力 
#include<iostream>
using namespace std;

bool chu[101];
int n,m,q,i,j;

int main()
{
    cin>>n>>m; 
    do
    {
        i++;
        if(i==n+1)
            i=1;
        if(!chu[i])
            q++;
        if(q==m)
        {
            q=0;
            cout<<i<<" ";
            chu[i]=true;
            j++;
        }
    }while(j!=n);
    return 0;
}

2)

///队列+数组模拟链表 
#include <iostream>
using namespace std;

const int N = 101;
int n,m,gs,k;
int q[N];///next is what(嘻嘻)

int main()
{
    cin>>n>>m;
    for(int i=1;i<n;i++)
        q[i]=i+1;
    q[n]=1;
    int nxt=n;
    while(gs<n)
    {
        k=1;
        while(k<m)
        {
            nxt=q[nxt];
            k++;
        }
        cout<<q[nxt]<<" ";
        gs++;
        ///delete the nxt
        q[nxt]=q[q[nxt]];
    }
    return 0;
}

 

posted @ 2017-07-16 16:45  夜雨声不烦  阅读(144)  评论(0编辑  收藏  举报