{ }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()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이

정렬 기준이 여럿일 때 쓰는 방법이 언어마다 달라요.
Python은 sorted(friends, key=key)의 열쇠로 튜플 (지났나, 월, 일, 이름)을 주면 앞 칸부터 차례로 견줘요.
날짜 견주기도 (m, d) < (M, D)처럼 튜플로 한 번에 돼요.
C++도 std::tie(…) < std::tie(…)로 같은 일을 하는데, std::sort에 넘기는 함수는 'a가 b보다 앞인가'를 bool로 돌려줘요.
JS·TS sort, C qsort, C# List.Sort, 크레이콘 목록.정렬(함수)에 넘기는 함수는 반대로 수를 돌려줘요: 앞이 먼저면 음수, 같으면 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·크레이콘은 <로 견줘요.
함정 하나: 월과 일로만 정렬하면 올해 이미 지난 생일이 맨 앞에 와요.
예시의 첫 줄이 joon(3월 14일)이 돼요.
함정 둘: 오늘이 생일인 친구는 지나지 않은 쪽이에요.
지났는지를 < 대신 <=로 물으면 예시의 mina가 맨 뒤로 가요.
함정 셋: 입력에서 읽은 월과 일은 문자열이에요.
수로 바꾸지 않고 견주면 "10"이 "9"보다, "12"가 "3"보다 앞이어서 예시가 mina, bora, sora, joon, hana, dan 차례가 돼요.
Python int(), JS Number(), 크레이콘 수로변환()으로 바꿔요.
함정 넷: JS sort에 C++처럼 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]);}