top1编程
← 返回题目
题解

排队看病

1 条题解

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

    P4835 排队看病(基础)

    解题思路

    第一步,理解"左边进"和"右边进"。 医院门口有一张长椅,病人一个接一个地来看病。医生助理会让新来的病人"从长椅的左边进去坐下"或者"从长椅的右边进去坐下"。从左边进的人会坐在长椅的最左边,从右边进的人会坐在长椅的最右边。题目要我们最后回答:长椅上从左到右坐着的人分别是谁。

    第二步,用双端队列模拟长椅。 这种"两头都能进人"的数据结构叫双端队列。我们用一个很大的数组 q 来模拟长椅,把数组的中间位置当作长椅的起点。准备两个指针:head 指向长椅最左边的人,tail 指向长椅最右边的人右边的那个空位。病人从左边进时,先让 head 减1,再把名字写进 q[head],这样新来的人就成了最左边的;病人从右边进时,把名字写进 q[tail],然后 tail 加1,这样新来的人就成了最右边的。

    第三步,举例走一遍。 样例中前三个病人都从左边进:LZZ、HSY、TSW,后进的人坐在更左边,所以这时从左到右是 TSW HSY LZZ。接着 LHS、WKA 从右边进,坐到最右边;LWJ 又从左边进,坐到最左边……最后一个 ZJX 从左边进,变成最左边的人。最后从左到右输出:ZJX ZZB LWJ TSW HSY LZZ LHS WKA HT DYL,和样例完全一致。

    第四步,注意数组大小和名字的存放。 n 最大是20000,最坏情况下有一半人从左边进、一半人从右边进,长椅左右两侧各需要约20000个位置,所以我们把数组开成40005格,并且从中间第20000格开始放人,保证左边和右边都不会越界。每个人的名字用一个字符数组存,长度为105,足够装下各种名字。

    参考代码

    // 排队看病:病号从长椅左边或右边进入,用数组模拟双端队列输出最终顺序
    #include <iostream>
    using namespace std;
    
    // 长椅上的座位,中间开始放人,左进往左、右进往右
    char q[40005][105];
    int head = 20000, tail = 20000;
    
    int main() {
        int n, a, i;
        char name[105];
        cin >> n;
        for (i = 0; i < n; i++) {
            cin >> a >> name;
            if (a == 0) {           // 从左边进,坐在最左边
                head--;
                int j = 0;
                while (name[j]) { q[head][j] = name[j]; j++; }
                q[head][j] = '\0';
            } else {                // 从右边进,坐在最右边
                int j = 0;
                while (name[j]) { q[tail][j] = name[j]; j++; }
                q[tail][j] = '\0';
                tail++;
            }
        }
        // 从左到右依次输出
        for (i = head; i < tail; i++) cout << q[i] << "\n";
        return 0;
    }
    

    复杂度分析

    n 最大为20000,每个病人进来时只做一次入座操作,最后从左到右输出 n 个名字,总共大约 2n 次操作,所以时间复杂度是 O(n)。空间上数组开 40005 格、每格存一个名字,空间复杂度是 O(n)。

    • 1