题目来源
兰州大学/湖南大学机试题
题目描述
Time Limit: 1000 ms
Memory Limit: 256 mb
n个猴子围坐一圈并按照顺时针方向从1到n编号,从第s个猴子开始进行1到m的报数,报数到第m的猴子退出报数,从紧挨它的下一个猴子重新开始1到m的报数,如此进行下去知道所有的猴子都退出为止。求给出这n个猴子的退出的顺序表。
输入输出格式
输入描述
有做组测试数据.每一组数据有两行,第一行输入n(表示猴子的总数最多为100)第二行输入数据s(从第s个猴子开始报数)和数据m(第m个猴子退出报数).当输入0 0 0时表示程序结束.
输出描述
每组数据的输出结果为一行,中间用逗号间隔。
输入输出样例
输入样例
10
2 5
5
2 3
0
0 0
输出样例
6,1,7,3,10,9,2,5,8,4
4,2,1,3,5
解题方法
思路和本质
这段代码是一个经典的约瑟夫环问题的变形
这里的变体在于不一定从第一个人那里开始报数
因此,我们创建队列的规则也发生了变化
原本可能是1,2,3,4,5
现在如果从第3个人报数,就需要是3,4,5,1,2这样
为什么用数组不方便?
第一个元素出队之后,还要将其余所有元素往前移一位,这样做以数组的特性来说,并不方便
可以使用链表,或者C++特有的队列库
具体可以怎么操作?
初始化队列
queue<int> q;
for(int i=0;i<n;i++){
q.push(s++);
if(s>n) s=1;
}
确定好猴子们排队的顺序:
3,4,5,1,2
没报到指定猴子的时候
就需要这个猴子出队跑到队伍后面:
int cur,num=1;//cur表示队头的当前元素
while(true){
cur=q.front();
q.pop();//出队
if(num==m){
//报数报到的处理逻辑
}
else{
q.push(cur);
num++;
}
}
报到指定猴子的时候
这个猴子就不回到后面,输出结果:
if(num==m){
num=1;//下一个报的数是1
if(q.empty()){
cout<<cur<<endl;
break;
}else{
cout<<cur<<",";
}
}
完整代码
#include <bits/stdc++.h>
using namespace std;
int main(){
int n,s,m;
while(cin>>n>>s>>m){
if(n==0&&s==0&&m==0) break;
queue<int> q;
//确定初始报数顺序
for(int i=0,j=s;i<n;i++){
q.push(s++);
if(s>n) s=1;
}
//报数过程
int cur,num=1;
while(true){
cur=q.front();
q.pop();//出队
if(num==m){
num=1;//下一个报的数是1
if(q.empty()){
cout<<cur<<endl;
break;
}else{
cout<<cur<<",";
}
}
else{
q.push(cur);
num++;
}
}
}
return 0;
}