病人排队

GitHub跳转原题关系图返回列表

把三条排队规则压成一个排序键(是否非老年人、老年人负年龄、登记序号),字典序比较一次排序同时完成分组、组内排序与平局裁决。

OJ: roj

题目 ID: 1183

难度:入门

标签:入门排序python

创建: 2026-09-29 22:27

更新: 2026-10-05 04:34

题目描述

病人登记看病,按三条规则排出看病顺序:年龄 ⩾60\geqslant 60 的老年人优先;老年人按年龄从大到小,年龄相同的按登记先后;非老年人一律按登记先后。数据范围 n<100n < 100,ID 为长度小于 1010 的数字字母串(可含前导零)。输入第一行 nn,其后 nn 行每行一个 ID 和一个年龄,按登记先后给出;输出每行一个 ID。样例输入 5 / 021075 40 / 004003 15 / 010158 67 / 021033 75 / 102012 30,期望输出 021033 / 010158 / 021075 / 004003 / 102012。

思路

把三条规则压成一个排序键 (age < 60, 老年人 ? -age : 0, 登记序号),按它排一次序再依次输出:第 1 位让老年人排前面,第 2 位让老年人年龄大的在前(非老年人固定为 0,年龄不参与),第 3 位由登记序号兜底裁决平局。ID 含前导零,必须按字符串处理。

参考代码

Python 版:

python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-09-29 22:28
# update_at: 2026-09-29 22:28

import sys

ELDERLY_AGE = 60  # 老年人门槛:年龄 >= 60 者优先看病


def visit_key(person: tuple[bytes, int, int]) -> tuple[bool, int, int]:
    """看病顺序键:老年人优先,老年人按年龄从大到小,登记序号兜底保持先来后到。"""
    _pid, age, idx = person
    # 非老年人的年龄不参与排序,统一记 0;同键由登记序号按输入先后打破平局
    return (age < ELDERLY_AGE, -age if age >= ELDERLY_AGE else 0, idx)


def solve() -> None:
    data = iter(sys.stdin.buffer.read().split())
    count = next(data)  # 病人个数
    # (ID, 年龄, 登记序号),登记序号即输入行的先后,也是同组内的平局裁决
    people: list[tuple[bytes, int, int]] = [
        (pid, int(age), i) for i, (pid, age) in enumerate(zip(data, data))
    ]
    people.sort(key=visit_key)
    print(b'\n'.join(pid for pid, _, _ in people).decode())


if __name__ == "__main__":
    solve()

C++ 版(同一算法):

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-10-05 04:33
 * update_at: 2026-10-05 04:33
 */
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;

typedef long long ll;

// n < 100,开 105 足够。
const ll MAXN = 105;

// 老年人门槛:年龄 >= 60 者优先看病。
const ll ELDERLY_AGE = 60;

// 病人:ID 含前导零,必须用字符串保存,不能转成整数。
struct Patient {
    string id;
    ll age;
    ll idx; // 登记序号,即输入行的先后,用来打破同组内的平局
};

Patient pat[MAXN]; // pat[i] 表示第 i 个登记的病人

ll n;

// 排队规则:老年人优先;老年人按年龄从大到小;其余情况一律按登记先后。
bool cmp_by_visit_order(const Patient &a, const Patient &b) {
    ll group_a = (a.age >= ELDERLY_AGE) ? 0 : 1; // 老年人取 0,排前面
    ll group_b = (b.age >= ELDERLY_AGE) ? 0 : 1;
    if (group_a != group_b) return group_a < group_b;
    // 同组内:老年人比年龄(大的在前),非老年人不比年龄(年龄一律看成 0)
    ll key_a = (a.age >= ELDERLY_AGE) ? -a.age : 0;
    ll key_b = (b.age >= ELDERLY_AGE) ? -b.age : 0;
    if (key_a != key_b) return key_a < key_b;
    return a.idx < b.idx; // 平局由登记序号裁决
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> n;
    for (ll i = 1; i <= n; i++) {
        cin >> pat[i].id >> pat[i].age;
        pat[i].idx = i;
    }

    sort(pat + 1, pat + n + 1, cmp_by_visit_order);

    for (ll i = 1; i <= n; i++) {
        cout << pat[i].id << "\n";
    }

    return 0;
}