题目背景
约瑟夫是一个无聊的人!!!
题目描述
n个人(n<=100)围成一圈,从第一个人开始报数,数到m的人出列,再由下一个人重新从1开始报数,数到m的人再出圈,……依次类推,直到所有的人都出圈,请输出依次出圈人的编号.
输入格式
n m
输出格式
出圈的编号
输入输出样例
输入 #1复制
10 3
输出 #1复制
3 6 9 2 7 1 8 5 10 4
说明/提示
m,n≤100
参考代码1.0: 用队列构成环,目的元素输出后删除,非目的元素插入队尾,即构成了一个环;
图解: k从1开始,不是3的时候就将其插入队尾,图上显示则是1排到9的后面,2排到1的后面。。。。
#include <queue>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f
#define MAX 5010
using namespace std;
int main()
{
int n, m;
int pos = 1;
cin >> n >> m;
queue<int> q;
for(int i = 1; i <= n; i++) q.push(i);
while(!q.empty())
{
if(pos == m)
{
cout << q.front() <<" ";
q.pop();
pos = 1;
}
else
{
pos++;
q.push(q.front());
q.pop();
}
}
return 0;
}
参考代码2.0: 用数组构成环,用k记录间隔,用pos记录下标,pos的变化为:pos = (pos+1)%n;可以保证成环循环;pos遇到为0值时,直接跳过直接后移,退出条件为输出数已到达n;
注意:k的初值为1,原因如图:
1、假设输入为n = 10, m = 3; k 开始时就已经指向了第一个元素,所以从1开始,清零的位置是第一组m的最后一个元素,还没开始下一组,所以清零;
2、与上一个不同,上一个输出直接删除,k仍然从1开始,但是k的指向到了输出的下一个,而数组只是清了零,指向的还是输出元素的位置。
#include <queue>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f
#define MAX 5010
using namespace std;
int S[101];
int main()
{
int n, m;
//num累计输出个数,pos记录下标的变化,k记录间隔(从1开始)
int pos = 0, k = 1,num = 0;
cin >> n >> m;
for(int i = 0; i < n; i++) S[i] = i + 1;
while(num < n)
{
if(k == m)
{
cout << S[pos] <<" ";
S[pos] = 0;
//累计num,清零k
num++; k = 0;
}
else
{
k++; pos = (pos+1) % n;
//若为0,则跳过,继续后移
while(S[pos] == 0) pos = (pos+1) % n;
}
}
return 0;
}