题目描述
有n个人围成一圈(编号为1~n),从第1号开始进行1、2、3报数,凡报3者就退出,下一个人又从1开始报数……直到最后只剩下一个人时为止。请问此人原来的位置是多少号?
输入格式:
测试数据有多组,处理到文件尾。每组测试输入一个整数n(5≤n≤100)。
输出格式:
对于每组测试,输出最后剩下那个人的编号。
输入样例:
10
28
69
输出样例:
4
23
68
思路:
约瑟夫环是比较经典的题目,是指n个人站成一排,第一个人和最后一个人手牵着手,(给每个人编号,编号从1到n)然后给定一个步长,按照这个步长开始淘汰人,如果步长是3的话,那就从第一个人开始,数过三个人之后就淘汰掉第三个,然后继续向下走,再次开始从第一个人开始,数三个步长就开始淘汰人,直到剩下最后一个人,要求输出最后一个人的编号。很明显我们可以想到使用队列的方式,假如步长是3,那么我们可以先把队首和队首第二个(小于3即可)
q.push(q.front());
q.pop();
然后把三个直接出队q.pop();
(这里可以嵌套一个循环:)
for(int j=1;j<3;j++){
q.push(q.front());
q.pop();
}
假如步长是3,前两个直接移到队尾,第三个直接出队;这样每隔三个就出队一个,而且保证前两个不会丢失,会直接移位到最后面,等待下次循环的时候再次使用,这也和现实比较相似。在这个循环外面可以再加一个循环,用来遍历队列,这样遍历到最后每次循环都会淘汰一个人,最后只剩下一个人,我们只需要输出队首元素即可。
这个题目也有一些难度,那就是输入的问题,输入的话我们可以使用while(scanf("%d",&n){定义队列并输入队列}
来解决。
详细代码如下:
#include<bits/stdc++.h>
using namespace std;
int n;
int main(){
while(scanf("%d",&n)!=EOF){
queue<int> q;
for(int i=1;i<=n;i++){
q.push(i);//自动添加i从1到n,存储到队列:1 2 3 4 5 6 7...n
}
for(int i=1;i<n;i++){
for(int j=1;j<3;j++){
q.push(q.front());
q.pop();
}
q.pop();
}
cout<<q.front();
}
}
运行结果图片: