{ }codelper
自定义排序P0376

生日先到的朋友排在前面

今天是 M 月 D 日。
给出 n 位朋友的名字和生日(月和日)。
从今天算起,按生日到来的先后顺序输出名字,每行一个。
生日就是今天的朋友是 0 天后,所以排在最前面。
生日的日期在今天之前的朋友,今年的生日已经过了,要等明年的生日。
这些朋友排在生日是今天或今天之后的朋友后面,从 1 月起按日期顺序排列。
生日是同一天的朋友之间,按名字的字典顺序排列(字母顺序;如果一个名字和另一个名字的开头部分完全相同,短的在前)。

输入
第一行给出 M 和 D,用一个空格隔开。
第二行给出 n。
接下来 n 行,每行给出一位朋友的名字、生日的月、生日的日,用一个空格隔开。
1 ≤ n ≤ 100。
名字是 1 ~ 10 个英文小写字母,并且互不相同。
今天和所有生日都是日历上存在的日期,不会给出 2 月 29 日
输出
n 行。
按生日到来的先后顺序,每行一个名字
样例 1 · stdin
10 5
6
mina 10 5
joon 3 14
sora 12 25
hana 9 30
dan 10 20
bora 12 25
stdout
mina
dan
bora
sora
joon
hana
main.py
输入(stdin)

运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 8 种语言题解

有多个排序标准时,各语言的写法不同。
Python 给 sorted(friends, key=key) 的键传元组 (过了没有, 月, 日, 名字),就会从前面的元素起依次比较。
比较日期也可以用元组一次完成:(m, d) < (M, D)。
C++ 用 std::tie(…) < std::tie(…) 做同样的事,不过传给 std::sort 的函数返回 bool,表示“a 是否在 b 前面”。
传给 JS、TS 的 sort、C 的 qsort、C# 的 List.Sort、Craykon 的 列表.排序(函数) 的函数则返回一个数:前者在先为负,相同为 0,后者在先为正。
JS 用 || 连接,如 a.passed - b.passed || a.month - b.month || …,结果是 0(相同)时就看下一个标准。
Java 用 Comparator.comparingInt(Friend::passed).thenComparingInt(Friend::month)… 把标准接起来。
名字在 C 里用 strcmp,在 C# 里用 string.CompareOrdinal,在 JS 和 Craykon 里用 < 比较。
陷阱一:只按月和日排序,今年已经过了的生日会排到最前面。
示例的第一行变成 joon(3 月 14 日)。
陷阱二:生日是今天的朋友属于还没过的一边。
判断是否已过时把 < 写成 <=,示例里的 mina 就会排到最后。
陷阱三:从输入读到的月和日是字符串。
不转成数就比较,"10" 排在 "9" 前面,"12" 排在 "3" 前面,示例会变成 mina、bora、sora、joon、hana、dan 的顺序。
Python 用 int(),JS 用 Number(),Craykon 用 转数字() 转换。
陷阱四:如果像 C++ 那样给 JS 的 sort 传一个返回 true/false 的函数,false 会被当作 0,也就是“相同”。
负数一次也不会出现,所以在 Node 里示例完全没有被排序,按输入顺序原样输出。

Pythonmain.py · 20 行
import sys lines = sys.stdin.read().split("\n")M, D = map(int, lines[0].split())n = int(lines[1])friends = []for line in lines[2:2 + n]:    name, m, d = line.split()    friends.append((name, int(m), int(d)))  # 정렬 열쇠: (올해 생일이 이미 지났나, 월, 일, 이름). 튜플은 앞 칸부터 차례로 견준다.# False가 True보다 앞이라 아직 지나지 않은 생일이 먼저 온다. 오늘이 생일이면 지나지 않은 것이다.def key(friend):    name, m, d = friend    return ((m, d) < (M, D), m, d, name)  for name, m, d in sorted(friends, key=key):    print(name)
JavaScriptmain.js · 21 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const [M, D] = lines[0].trim().split(" ").map(Number);const n = Number(lines[1]);const friends = [];for (let i = 2; i < 2 + n; i++) {  const [name, m, d] = lines[i].trim().split(" ");  const month = Number(m);  const day = Number(d);  // 올해 생일이 이미 지났으면 1, 아니면 0. 오늘이 생일이면 지나지 않은 것이다.  const passed = month < M || (month === M && day < D) ? 1 : 0;  friends.push({ name, month, day, passed });}// 견주는 함수는 앞이 먼저면 음수, 뒤가 먼저면 양수를 돌려준다. 0이면 || 뒤의 다음 기준으로 넘어간다.friends.sort(  (a, b) =>    a.passed - b.passed ||    a.month - b.month ||    a.day - b.day ||    (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));console.log(friends.map((f) => f.name).join("\n"));
TypeScriptmain.ts · 30 行
import { readFileSync } from "node:fs"; interface Friend {  name: string;  month: number;  day: number;  passed: number; // 올해 생일이 이미 지났으면 1, 아니면 0} const lines: string[] = readFileSync(0, "utf8").split("\n");const [M, D]: number[] = lines[0].trim().split(" ").map(Number);const n: number = Number(lines[1]);const friends: Friend[] = [];for (let i = 2; i < 2 + n; i++) {  const [name, m, d]: string[] = lines[i].trim().split(" ");  const month = Number(m);  const day = Number(d);  // 오늘이 생일이면 지나지 않은 것이다.  const passed = month < M || (month === M && day < D) ? 1 : 0;  friends.push({ name, month, day, passed });}// 견주는 함수는 앞이 먼저면 음수, 뒤가 먼저면 양수를 돌려준다. 0이면 || 뒤의 다음 기준으로 넘어간다.friends.sort(  (a: Friend, b: Friend): number =>    a.passed - b.passed ||    a.month - b.month ||    a.day - b.day ||    (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));console.log(friends.map((f: Friend): string => f.name).join("\n"));
JavaMain.java · 38 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.Comparator;import java.util.List; public class Main {    // passed: 올해 생일이 이미 지났으면 1, 아니면 0    record Friend(String name, int month, int day, int passed) {}     public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        String[] today = in.readLine().trim().split(" ");        int M = Integer.parseInt(today[0]);        int D = Integer.parseInt(today[1]);        int n = Integer.parseInt(in.readLine().trim());        List<Friend> friends = new ArrayList<>();        for (int i = 0; i < n; i++) {            String[] parts = in.readLine().trim().split(" ");            int month = Integer.parseInt(parts[1]);            int day = Integer.parseInt(parts[2]);            // 오늘이 생일이면 지나지 않은 것이다.            int passed = (month < M || (month == M && day < D)) ? 1 : 0;            friends.add(new Friend(parts[0], month, day, passed));        }        // 기준을 차례로 잇는다: 앞 기준이 같을 때만 다음 기준을 본다.        friends.sort(Comparator.comparingInt(Friend::passed)                .thenComparingInt(Friend::month)                .thenComparingInt(Friend::day)                .thenComparing(Friend::name));        StringBuilder out = new StringBuilder();        for (Friend f : friends) {            out.append(f.name()).append('\n');        }        System.out.print(out);    }}
C#Main.cs · 39 行
using System;using System.Collections.Generic;using System.Text; class Program{    static void Main()    {        string[] today = Console.ReadLine().Trim().Split(' ');        int M = int.Parse(today[0]);        int D = int.Parse(today[1]);        int n = int.Parse(Console.ReadLine().Trim());        // passed: 올해 생일이 이미 지났으면 1, 아니면 0        var friends = new List<(string name, int month, int day, int passed)>();        for (int i = 0; i < n; i++)        {            string[] parts = Console.ReadLine().Trim().Split(' ');            int month = int.Parse(parts[1]);            int day = int.Parse(parts[2]);            // 오늘이 생일이면 지나지 않은 것이다.            int passed = (month < M || (month == M && day < D)) ? 1 : 0;            friends.Add((parts[0], month, day, passed));        }        // 견주는 함수는 앞이 먼저면 음수, 같으면 0, 뒤가 먼저면 양수를 돌려준다.        friends.Sort((a, b) =>        {            if (a.passed != b.passed) return a.passed.CompareTo(b.passed);            if (a.month != b.month) return a.month.CompareTo(b.month);            if (a.day != b.day) return a.day.CompareTo(b.day);            return string.CompareOrdinal(a.name, b.name); // 글자 코드 순서로 견준다        });        var sb = new StringBuilder();        foreach (var f in friends)        {            sb.Append(f.name).Append('\n');        }        Console.Write(sb);    }}
C++main.cpp · 32 行
#include <algorithm>#include <iostream>#include <string>#include <tuple>#include <vector>using namespace std; struct Friend {    string name;    int month, day;    bool passed; // 올해 생일이 이미 지났는가}; int main() {    int M, D, n;    cin >> M >> D >> n;    vector<Friend> friends(n);    for (Friend &f : friends) {        cin >> f.name >> f.month >> f.day;        // pair는 앞 칸부터 견준다. 오늘이 생일이면 지나지 않은 것이다.        f.passed = make_pair(f.month, f.day) < make_pair(M, D);    }    // C++의 견주는 함수는 "a가 b보다 앞인가"를 bool로 돌려준다.    // tie로 묶으면 앞 칸부터 차례로 견준다(false가 true보다 앞).    sort(friends.begin(), friends.end(), [](const Friend &a, const Friend &b) {        return tie(a.passed, a.month, a.day, a.name) < tie(b.passed, b.month, b.day, b.name);    });    for (const Friend &f : friends) {        cout << f.name << '\n';    }    return 0;}
Cmain.c · 37 行
#include <stdio.h>#include <stdlib.h>#include <string.h> typedef struct {    char name[11];    int month, day;    int passed; /* 올해 생일이 이미 지났으면 1, 아니면 0 */} Friend; /* qsort가 부르는 견주는 함수: 앞이 먼저면 음수, 같으면 0, 뒤가 먼저면 양수 */static int compare_friends(const void *pa, const void *pb) {    const Friend *a = pa;    const Friend *b = pb;    if (a->passed != b->passed) return a->passed - b->passed;    if (a->month != b->month) return a->month - b->month;    if (a->day != b->day) return a->day - b->day;    return strcmp(a->name, b->name);} int main(void) {    int M, D, n;    static Friend friends[100];    scanf("%d %d", &M, &D);    scanf("%d", &n);    for (int i = 0; i < n; i++) {        Friend *f = &friends[i];        scanf("%10s %d %d", f->name, &f->month, &f->day);        /* 오늘이 생일이면 지나지 않은 것이다. */        f->passed = (f->month < M || (f->month == M && f->day < D)) ? 1 : 0;    }    qsort(friends, n, sizeof(Friend), compare_friends);    for (int i = 0; i < n; i++) {        printf("%s\n", friends[i].name);    }    return 0;}
Craykonmain.cray · 60 行
오늘 = 控制台.读数字();M = 오늘[0];D = 오늘[1];n = 控制台.读行().转数字();names = [];months = [];days = [];passed = []; // 올해 생일이 이미 지났으면 1, 아니면 0order = []; // 친구 번호를 담아 두고 이 목록을 정렬한다循环 (i = 0; i < n; i++){    parts = 控制台.读行().去空白().分割(" ");    m = parts[1].转数字();    d = parts[2].转数字();    names.添加(parts[0]);    months.添加(m);    days.添加(d);    // 오늘이 생일이면 지나지 않은 것이다    如果 (m < M || m == M && d < D)    {        passed.添加(1);    }    否则    {        passed.添加(0);    }    order.添加(i);} // 견주는 함수: 앞이 먼저면 음수, 같으면 0, 뒤가 먼저면 양수를 돌려준다먼저오는생일(a, b){    如果 (passed[a] != passed[b])    {        返回 passed[a] - passed[b];    }    如果 (months[a] != months[b])    {        返回 months[a] - months[b];    }    如果 (days[a] != days[b])    {        返回 days[a] - days[b];    }    如果 (names[a] < names[b])    {        返回 -1;    }    如果 (names[a] > names[b])    {        返回 1;    }    返回 0;} order.排序(먼저오는생일);遍历 (i 在 order){    控制台.输出(names[i]);}