7.9 约瑟夫问题—数组实现
【问题描述】
有m个人,其编号分别为1-m。按顺序围成一个圈,现在给定一个数n,从第一个人开始依次报数,报到n的人出圈,
然后再从下一个人开始继续从1开始依次报数报到n的人再出圈,…如此循环,直到最后一个人出圈为止。编程输出所有人出圈的顺序。
输入格式
一行两个正整数m和n,之间用一个空格隔开,1≤m<100,1≤n≤32767。
输出格式
输出m行,每行一个正整数,表示依次出圈的人的编号。
输入样例
85
输出样例
5
2
8
7
1
4
6
3
问题分析
定义bool型数组p,表示每个人在圈中的状态。假设p[i]为true表示第i个人还在圈中,
p[i]为 false表示第i个人已出圈。模拟报数的过程,从第一个人(i=1)开始报数,定义计数
器j,初始化为0,如果p[i]为tmue,则j加1,当j为n时,报到的这个人出圈(p[i]=false,且
j=0),…直到所有人都已出圈。程序实现时,另外设计一个计数器t,记录圈中的剩余人数,
初始化为m。
题解代码:
#include<iostream>
#include<cstring>
#include<list>
using namespace std;
int m,n;
list<int> l;
int main(){
scanf("%d%d",&m,&n);
int cnt1=m,cnt2=1;//cnt2表示计n数
bool p[101];
memset(p,false,sizeof(p));
int i=0;//i表示指针
while(cnt1){
if(i==m) i=0;
if(p[i]==true){
i++;
continue;
}
if(cnt2==n){
cnt2=1;
p[i]=true;
cnt1--;
printf("%d\n",i+1);
i++;
}
else{
i++;
cnt2++;
}
}
return 0;
}
题解思路:
这道题的思路即为构造一个环,使得对应坐标指针i能在队列中从头到尾的一次又一次游走,我们先定义i作为1到m的指针,定义cnt1为元素个数,cnt2为每次计数1到n时的值,即约瑟夫环1到n的指针。定义一个bool型数组p,代表当前元素是否已出列。
具体实现:用一个while循环判断cnt1元素个数是否为0,循环中每出列一个元素,则cnt1--,若cnt1==0则元素已全部出列,跳出循环。
while中,判断i的值,若i==m说明已到达结尾外,需返回队列开头,令i=0。(注意,我们取得元素下标为0到m-1),若p[i]==true,说明已出列,则continue进入循环下一阶段,若p[i]==false,则在队列中,cnt2为计数1到n中的第几个,若为n说明应当删去,cnt2=1,printf输出对应的值;若cnt2小于n,则cnt2++,进入下次循环
(注意,我的每次运算中i与cnt2指针的值都在该循环阶段之前已计算出,计算前与计算后的逻辑关系同学们需要好好思索,搞清楚)