top1编程
← 返回题目
题解

排队问题

1 条题解

  • 0
    @ 2026-8-7 12:55:51

    P4834 排队问题(入门)

    解题思路

    第一步,看懂游戏规则。 有 n 个人排成一队,从左到右按照"1、2、1、2……"的顺序报数。报到数字1的人立刻出列,离开队伍;报到数字2的人不出列,而是立刻跑到队伍的最右边重新排队。报完一轮之后又从队伍最左边开始,继续"1、2、1、2"地报数,一直重复,直到所有人都出列为止。题目要我们输出每个人出列的顺序。

    第二步,用队列来模拟这个队伍。 队列的特点是"先进先出",队头出、队尾进,正好和题目中"从左边出列、到右边排队"的过程一致。我们用数组 q 存放队伍,用两个下标 head 和 tail 分别指向队头和队尾。每次从队头取出一个人,就是 q[head],然后 head 加1。

    第三步,用变量控制报数。 准备一个变量 c,表示"这次该报到几",它只在1和2之间切换。每次从队头取出一个人 x:如果 c 等于1,这个人出列,直接输出它的编号,然后把 c 改成2;如果 c 等于2,这个人不出列,而是把它放到队尾,也就是执行 q[tail++]=x,然后把 c 改成1。这样反复执行,直到 head 等于 tail,队伍空了为止。

    第四步,拿样例验证一遍。 队伍是 1 2 3 4 5 6 7 8:1报到1出列,2报到2跑到队尾,3报到1出列,4报到2跑到队尾……依次下去,出列顺序正好是 1 3 5 7 2 6 4 8,和题目给出的样例一模一样。注意输出时每个编号之间用一个空格隔开。

    第五步,考虑数组大小。 n 最大是100,每个人最多被移到队尾一次,所以队列长度最多到 2n 左右,数组开205个格子就足够用了。

    参考代码

    // 排队问题:1、2、1、2报数,报1出列,报2到队尾,模拟出列顺序
    #include <iostream>
    using namespace std;
    
    int main() {
        int q[205];
        int n, i;
        cin >> n;
        for (i = 0; i < n; i++) cin >> q[i];
        int head = 0, tail = n;  // 队头、队尾指针
        int c = 1;               // 当前报的数,1或2
        bool first = true;
        while (head < tail) {
            int x = q[head++];   // 队头出队
            if (c == 1) {        // 报到1,出列
                if (!first) cout << " ";
                first = false;
                cout << x;
                c = 2;
            } else {             // 报到2,移到队尾
                q[tail++] = x;
                c = 1;
            }
        }
        cout << endl;
        return 0;
    }
    

    复杂度分析

    n 最大为100,每个人在队伍中最多被取出一次,也最多被移到队尾一次,总共操作不超过 2n 次,所以时间复杂度是 O(n)。空间上数组 q 最多需要 2n 个格子,空间复杂度也是 O(n)。

    • 1