【问题描述】
有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指针的值都在该循环阶段之前已计算出,计算前与计算后的逻辑关系同学们需要好好思索,搞清楚)