【洛谷】P1996 约瑟夫问题(队列 or 模拟)题解

原题链接: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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值