目录

c_队列习题

c++_队列习题

约瑟夫问题

输入: 每行是用空格分开的三个整数,第一个是n,第二个是p,第三个是m (0 < m,n < 300)。

最后一行是:0 0 0

(即n个人围成一圈,从p号开始抱起,当报到m时就退圈)

输出: 按出圈的顺序输出编号,编号之间以逗号间隔。

思路:

我们可知,先到的小孩先报数,所以我们需要借助一个队列;

而且我们需要实现的是一个循环队列( 因为一个小孩报完数,后面可能还需要他再报数)我们可以通过将一个数出队再入队的时候实现循环队列;

  1. 将n个小孩放入队列(no是他们的编号)

  2. 第一轮报数(用say表示), 从p开始报;我们一开始让着n个元素入队的时候就可以用报数的顺序进行入队。

  3. 后续报数:报数即为取出队首元素;打印他的值。

    如果报的数不是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);

            }
        }
    }
}

https://i-blog.csdnimg.cn/direct/34d0c456abb748e2939ee9d27d3ef295.png