c_队列习题
目录
c++_队列习题
约瑟夫问题
输入: 每行是用空格分开的三个整数,第一个是n,第二个是p,第三个是m (0 < m,n < 300)。
最后一行是:0 0 0
(即n个人围成一圈,从p号开始抱起,当报到m时就退圈)
输出: 按出圈的顺序输出编号,编号之间以逗号间隔。
思路:
我们可知,先到的小孩先报数,所以我们需要借助一个队列;
而且我们需要实现的是一个循环队列( 因为一个小孩报完数,后面可能还需要他再报数)我们可以通过将一个数出队再入队的时候实现循环队列;
将n个小孩放入队列(no是他们的编号)
第一轮报数(用say表示), 从p开始报;我们一开始让着n个元素入队的时候就可以用报数的顺序进行入队。
后续报数:报数即为取出队首元素;打印他的值。
如果报的数不是m,则say++,再将该元素放回队列
如果报的数是m,取出队首元素后,若队列不为空,则直接打印元素;若队列为空,则打印元素并退出循环。
int main() {
queue<int> myQueue;
int n, p, m;
while (1) {
//第一个是n,第二个是p,第三个是m
scanf("%d%d%d", &n, &p, &m);
if (n == 0 && p == 0 && m == 0) {
break;
}
//生成第一轮报数的队列(即将孩子编号放入队列)
//p,p+1,.....n,1,2,....p-1
int no = p;//no是孩子编号
for (int i = 0; i < n; i++) {
myQueue.push(no);
no++;
if (no > n) {
no = 1;
}
}
//开始报数
int say = 1;
while (1) {
int cur = myQueue.front();
myQueue.pop();
//如果报的数是m
if (say == m) {
say = 1;
//该小孩读到了m,且出去后队列为空;这时打印完其编号后就退出循环了。
if (myQueue.empty()) {
printf("%d\n", cur);
break;
}
else {
printf("%d,", cur);
}
}
else {
//如果报的数字不是m
say++;
//把该小孩重新放回队列中
myQueue.push(cur);
}
}
}
}