top1编程
← 返回题目
题解

童童去存款

1 条题解

  • 0
    @ 2026-8-6 2:22:20

    P4840 童童去存款(基础)

    解题思路

    **第一步,想想银行窗口是怎么工作的。**银行里有两个窗口:A窗口速度是B窗口的2倍,也就是说A窗口处理完2个顾客的时间里,B窗口只处理完1个顾客。所以我们可以把时间分成一小段一小段,每一段里A窗口完成2个人、B窗口完成1个人。如果两个窗口同时完成,A窗口的顾客先出来。

    **第二步,怎么安排顾客排队?**题目规定:编号是奇数的顾客去A窗口,编号是偶数的顾客去B窗口。我们就用两个队列分别存放他们,一个叫A队,一个叫B队。队头(ha、hb)表示下一个要处理的人,队尾(ta、tb)表示新来的人排在哪里。

    **第三步,按照一轮一轮输出。**每一轮先看A队:从队头连续处理2个顾客(如果A队还有人的话),边处理边输出;再处理B队队头的1个顾客并输出。这样一轮一轮做下去,直到两个队都空了,就得到了完整的完成顺序。

    **第四步,想一想边界情况。**如果A队只剩下1个人,而B队还有很多人,那么这一轮A队只处理这1个人,B队还是处理1个,下一轮A队没人的话就直接处理B队。比如样例中A队有6个人、B队有2个人,最后一轮A队输出13和15后,B队已经没人了,游戏结束。

    **举一个具体的例子。**输入是 8 2 1 3 9 4 11 13 15:奇数是1、3、9、11、13、15,偶数是2、4。第一轮A队出1、3,B队出2;第二轮A队出9、11,B队出4;第三轮A队出13、15,B队空了。合起来就是 1 3 2 9 11 4 13 15,和样例一模一样。

    参考代码

    // P4840 童童去存款:奇数去A窗口(每轮2个),偶数去B窗口(每轮1个),同轮A先输出
    #include <iostream>
    #include <cstdio>
    using namespace std;
    int n, num;
    int qa[1005], qb[1005];
    int ha, ta, hb, tb;
    int main() {
        scanf("%d", &n);
        for (int i = 0; i < n; i++) {
            scanf("%d", &num);
            if (num % 2) qa[ta++] = num;  // 奇数进A窗口队列
            else qb[tb++] = num;          // 偶数进B窗口队列
        }
        int first = 1;
        while (ha < ta || hb < tb) {
            for (int i = 0; i < 2 && ha < ta; i++) {  // A窗口每轮处理2个
                if (!first) printf(" ");
                first = 0;
                printf("%d", qa[ha++]);
            }
            if (hb < tb) {  // B窗口每轮处理1个
                if (!first) printf(" ");
                first = 0;
                printf("%d", qb[hb++]);
            }
        }
        printf("\n");
        return 0;
    }
    

    复杂度分析

    把每个顾客分成奇数、偶数各入队一次,输出时每个人也只被处理一次,所以总时间是O(N),其中N是顾客总数(N≤1000)。数组只需要存下所有顾客,空间也是O(N)。这个题目其实就是模拟两个速度不同的窗口,代码很直接。

    • 1