原题链接:https://www.luogu.org/problem/P1996
题目背景
约瑟夫是一个无聊的人!!!
题目描述
n个人(n<=100)围成一圈,从第一个人开始报数,数到m的人出列,再由下一个人重新从1开始报数,数到m的人再出圈,……依次类推,直到所有的人都出圈,请输出依次出圈人的编号.
输入输出格式
输入格式:
n m
输出格式:
出圈的编号
输入输出样例
输入样例#1:
10 3
输出样例#1:
3 6 9 2 7 1 8 5 10 4
说明
时空限制:1000ms 125M
m,n≤100
思路:这道题比较水,可以用队列来做,也可以直接模拟。
第一种:队列
先把所有人的编号压入队列,当队列不为空队列,每一次判断队列头元素,如果报数到了m,则输出头元素编号,删除头元素;否则复制头元素插入到尾部,再删除头元素。这样就构成了队列的循环。
代码如下:
#include <iostream>
#include <cstdio>
#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); //把每个人的编号压入队列
int sum=1; //报数
while(!q.empty()) //当队列不为空队列
{
if(sum==m) //如果报到m
{
cout<<q.front()<<" "; //输出出局的人的编号
q.pop(); //该人出局
sum=1; //重新报数
}
else
{
sum++;
q.push(q.front()); //复制队头元素插入队尾
q.pop(); //队头元素还存在,所以要出局
}
}
cout<<endl;
return 0;
}
第二种:模拟
因为人围成了一个圈,所以遍历n,不断循环进行报数,用数组b来标记是否送出,计数器total来报数,sum来记录送走的人数。当报的数达到了m,则输出该人编号,标记为已送出,total重新计数,sum+1。当然,如果送走人数达到了n,则跳出循环。如果一圈数完了,则 i 重新计数,进行下一圈报数。
代码如下:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
int n,m,i;
scanf("%d%d",&n,&m);
int total=0,sum=0; //count记录是否达到了m,sum记录送走的人数,均要初始化
bool b[102]; //定义b数组来标记是否已经送出,false表示未送出,true表示已送出
memset(b,false,sizeof(b)); //全部标记为未送出
for(i=1;i<=n;i++)
{
if(!b[i]) //如果未送出
{
total++; //报数
if(total==m) //如果报的数达到了m
{
printf("%d ",i); //输出该人编号
b[i]=true; //标记为已送出
total=0; //count赋值为0重新计数
sum++; //送出人数加1
}
if(sum==n) //如果人数已送完,跳出循环
break;
}
if(i==n) //如果一圈完了,则重新开始下一圈
i=0;
}
return 0;
}