题解:洛谷 P1104 生日

【题目来源】

洛谷:P1104 生日 - 洛谷(luogu.com.cn)

【题目描述】

cjf 君想调查学校 OI 组每个同学的生日,并按照年龄从大到小的顺序排序。但 cjf 君最近作业很多,没有时间,所以请你帮她排序。

【输入】

输入共有 \(n+1\) 行,

\(1\) 行为 OI 组总人数 \(n\)

\(2\) 行至第 \(n+1\) 行分别是每人的姓名 \(s\)、出生年 \(y\)、月 \(m\)、日 \(d\)

【输出】

输出共有 \(n\) 行,

\(n\) 个生日从大到小同学的姓名。(如果有两个同学生日相同,输入靠后的同学先输出)

【输入样例】

3
Yangchu 1992 4 23
Qiujingya 1993 10 13
Luowen 1991 8 1

【输出样例】

Luowen
Yangchu
Qiujingya

【核心思想】

  1. 问题分析:给定 \(n\) 名学生的姓名和出生日期(年、月、日),要求按年龄从大到小排序(即出生日期越早越靠前)。如果两个学生生日完全相同,则输入靠后的学生排在前面。本质是一个多关键字排序问题,排序优先级为:年升序 → 月升序 → 日升序 → 输入顺序降序。

  2. 算法选择

    • 结构体 + 自定义比较函数:使用结构体存储姓名、年、月、日和输入顺序。利用 std::sort 配合自定义比较函数,实现按年龄从大到小(即日期从小到大)排序,生日相同时按输入顺序降序。
    • 复杂度:时间复杂度 \(O(n \log n)\),空间复杂度 \(O(n)\)
  3. 关键步骤

    • 读入:读取 \(n\),然后对于每个学生 \(i\),读入姓名、年、月、日,记录 order = i(从 0 开始)。
    • 排序:比较函数 cmp 先按年、月、日升序比较,若完全相等则按 order 降序(即后输入的先输出)。
    • 输出:按排序后的顺序输出姓名。
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n \log n)\)
    • 空间复杂度:\(O(n)\)
  5. 多关键字排序

    • 年龄与日期关系:年龄大 = 出生日期早(年小、月小、日小)。
    • 稳定排序处理同生日:使用输入顺序作为第四关键字,并降序排列,以满足“输入靠后的先输出”。
    • 适用场景:这类“按日期排序”问题,是结构体排序的典型应用。

【解题思路】

【算法标签】

普及- #其他排序

【代码详解】

#include <bits/stdc++.h>  // 包含常用的头文件
using namespace std;

// 定义学生结构体,包含姓名、出生年、月、日以及输入顺序
struct student {
    string name;  // 学生姓名
    int year, mon, day;  // 出生日期:年、月、日
    int order;  // 输入顺序,用于处理同一天生日的学生
}ss[105];  // 定义一个最多可以存储105个学生的数组

// 自定义比较函数,用于排序
bool cmp(student s1, student s2)
{
    // 1. 首先按出生年份从小到大排序
    if (s1.year != s2.year) return s1.year < s2.year;
    // 2. 如果年份相同,按月份从小到大排序
    if (s1.mon != s2.mon) return s1.mon < s2.mon;
    // 3. 如果月份相同,按日期从小到大排序
    if (s1.day != s2.day) return s1.day < s2.day;
    // 4. 如果日期也相同,按输入顺序从后往前排序(order大的排在前面)
    return s1.order > s2.order;
}

int main()
{
    int n;  // n: 学生总数
    cin >> n;  // 输入学生总数

    // 输入每个学生的姓名和出生日期,并记录输入顺序
    for (int i=0; i<n; i++) {
        cin >> ss[i].name >> ss[i].year >> ss[i].mon >> ss[i].day;
        ss[i].order = i;  // 记录输入顺序
    }

    // 对学生数组进行排序,排序规则由cmp函数决定
    sort(ss, ss+n, cmp);

    // 输出排序后的学生姓名
    for (int i=0; i<n; i++) {
        cout << ss[i].name << endl;
    }

    return 0;  // 程序结束
}

【运行结果】

3
Yangchu 1992 4 23
Qiujingya 1993 10 13
Luowen 1991 8 1
Luowen
Yangchu
Qiujingya
posted @ 2026-08-31 09:23  团爸讲算法  阅读(17)  评论(0)    收藏  举报