{ }codelper
인터페이스제네릭P0081

하나로 쓰는 최댓값

넓이를 가진 도형 인터페이스를 만들고, 직사각형과 직각삼각형 클래스가 그 인터페이스를 구현하게 하라.
그리고 목록에서 가장 큰 것을 찾는 제네릭 함수 하나를 만들어 정수 목록, 낱말 목록, 도형 목록에 모두 써라.
가장 큰 것이 여럿이면 목록에서 가장 앞의 것을 고른다.
입력은 다섯 부분이다: 정수 개수 n, 정수 n개(한 줄), 낱말 개수 m, 낱말 m개(한 줄), 도형 개수 k, 그리고 도형 k줄.
도형 줄은 "rect w h"(가로 w, 세로 h인 직사각형, 넓이 w × h) 또는 "tri b h"(밑변 b, 높이 h인 직각삼각형, 넓이 b × h ÷ 2)이다.
세 줄을 출력하라: 가장 큰 정수, 사전 순으로 가장 뒤에 오는 낱말, 그리고 넓이가 가장 큰 도형의 "번호 도형줄"(번호는 1부터 센 입력 차례, 도형줄은 입력 그대로).

입력
1 ≤ n, m, k ≤ 1000.
-1,000,000,000 ≤ 정수 ≤ 1,000,000,000.
낱말은 영어 소문자 1 ~ 10글자.
1 ≤ w, h, b ≤ 10,000(정수)
출력
세 줄
예시 1 · stdin
4
9 10 -3 10
3
banana apple cherry
3
rect 2 2
tri 3 3
tri 9 1
stdout
10
cherry
2 tri 3 3
main.py
입력(stdin)

실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

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

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

이 문제는 인터페이스와 제네릭이 있는 TypeScript·Java·C#만 받아요(Python·JS는 타입을 적지 않아서 제네릭이 따로 없고, C에는 둘 다 없어요.
C++ 템플릿은 모양이 많이 달라서 이 문제에서는 뺐어요).
세 언어는 "서로 비교할 수 있는 T"를 다르게 말해요.
Java <T extends Comparable<? super T>>, C# where T : IComparable<T>처럼 타입에 제약을 걸고, 도형 인터페이스가 Comparable<Shape>·IComparable<IShape>를 이어받아 넓이로 비교하는 법을 한 번만 정해요(Java default 메서드, C# 8의 인터페이스 기본 구현).
Java는 List<int>를 못 써서 List<Integer>로 담아요.
TS는 수와 문자열에 비교 메서드가 없으니 argMax<T>(items: T[], compare: (a: T, b: T) => number)처럼 비교 함수를 함께 받는 게 자연스러워요.
함정: TS에서 수를 Number()로 바꾸지 않고 문자열 그대로 <로 비교하면 "9" > "10"처럼 문자열 순서가 돼요(타입을 T로 두면 컴파일러도 못 잡아요).
삼각형 넓이를 정수 나눗셈 b * h / 2로 구하면 4.5가 4로 잘려 넓이 4인 사각형과 같아져요.
넓이의 두 배 b * h로 비교하면 정수로만 셀 수 있어요.
같은 넓이일 때 앞의 것을 고르려면 > 0일 때만 바꾸고, >= 0이면 마지막 것을 골라요.
C# string의 CompareTo는 문화권 규칙으로 비교하지만(순수 코드 순서는 string.CompareOrdinal), 이 문제는 소문자만 써서 결과가 같아요.

TypeScriptmain.ts · 45 줄
import { readFileSync } from "node:fs"; interface Shape {  twiceArea(): number; // 넓이의 두 배(삼각형도 정수로 비교하려고)  describe(): string;} class Rect implements Shape {  private w: number;  private h: number;  constructor(w: number, h: number) { this.w = w; this.h = h; }  twiceArea(): number { return 2 * this.w * this.h; }  describe(): string { return `rect ${this.w} ${this.h}`; }} class Tri implements Shape {  private b: number;  private h: number;  constructor(b: number, h: number) { this.b = b; this.h = h; }  twiceArea(): number { return this.b * this.h; }  describe(): string { return `tri ${this.b} ${this.h}`; }} // 가장 큰 것의 자리(같으면 앞의 것). T가 무엇이든 비교 방법만 받으면 된다function argMax<T>(items: T[], compare: (a: T, b: T) => number): number {  let best = 0;  for (let i = 1; i < items.length; i++) if (compare(items[i], items[best]) > 0) best = i;  return best;} const lines: string[] = readFileSync(0, "utf8").split("\n");const nums: number[] = lines[1].trim().split(" ").map(Number);const words: string[] = lines[3].trim().split(" ");const k: number = Number(lines[4]);const shapes: Shape[] = [];for (let i = 0; i < k; i++) {  const [kind, a, b] = lines[5 + i].trim().split(" ");  shapes.push(kind === "rect" ? new Rect(Number(a), Number(b)) : new Tri(Number(a), Number(b)));} const byOrder = <T>(a: T, b: T): number => (a < b ? -1 : a > b ? 1 : 0);console.log(nums[argMax(nums, (a, b) => a - b)]);console.log(words[argMax(words, byOrder)]);const s = argMax(shapes, (a, b) => a.twiceArea() - b.twiceArea());console.log(`${s + 1} ${shapes[s].describe()}`);
JavaMain.java · 58 줄
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.List; interface Shape extends Comparable<Shape> {    int twiceArea(); // 넓이의 두 배(삼각형도 정수로 비교하려고)    String describe();     // 넓이로 비교하는 법을 인터페이스가 한 번만 정한다    default int compareTo(Shape other) { return Integer.compare(twiceArea(), other.twiceArea()); }} class Rect implements Shape {    private final int w, h;    Rect(int w, int h) { this.w = w; this.h = h; }    public int twiceArea() { return 2 * w * h; }    public String describe() { return "rect " + w + " " + h; }} class Tri implements Shape {    private final int b, h;    Tri(int b, int h) { this.b = b; this.h = h; }    public int twiceArea() { return b * h; }    public String describe() { return "tri " + b + " " + h; }} public class Main {    /** 가장 큰 것의 자리(같으면 앞의 것). 서로 비교할 수 있는 T라면 무엇이든. */    static <T extends Comparable<? super T>> int argMax(List<T> items) {        int best = 0;        for (int i = 1; i < items.size(); i++)            if (items.get(i).compareTo(items.get(best)) > 0) best = i;        return best;    }     public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        in.readLine();        List<Integer> nums = new ArrayList<>(); // List<int>는 안 된다        for (String t : in.readLine().trim().split(" ")) nums.add(Integer.parseInt(t));        in.readLine();        List<String> words = List.of(in.readLine().trim().split(" "));        int k = Integer.parseInt(in.readLine().trim());        List<Shape> shapes = new ArrayList<>();        for (int i = 0; i < k; i++) {            String[] p = in.readLine().trim().split(" ");            int a = Integer.parseInt(p[1]), b = Integer.parseInt(p[2]);            shapes.add(p[0].equals("rect") ? new Rect(a, b) : new Tri(a, b));        }         System.out.println(nums.get(argMax(nums)));        System.out.println(words.get(argMax(words)));        int s = argMax(shapes);        System.out.println((s + 1) + " " + shapes.get(s).describe());    }}
C#Main.cs · 61 줄
using System;using System.Collections.Generic;using System.Linq; interface IShape : IComparable<IShape>{    int TwiceArea(); // 넓이의 두 배(삼각형도 정수로 비교하려고)    string Describe();     // 넓이로 비교하는 법을 인터페이스가 한 번만 정한다(C# 8의 기본 구현)    int IComparable<IShape>.CompareTo(IShape other) => TwiceArea().CompareTo(other.TwiceArea());} class Rect : IShape{    private readonly int w, h;    public Rect(int w, int h) { this.w = w; this.h = h; }    public int TwiceArea() => 2 * w * h;    public string Describe() => $"rect {w} {h}";} class Tri : IShape{    private readonly int b, h;    public Tri(int b, int h) { this.b = b; this.h = h; }    public int TwiceArea() => b * h;    public string Describe() => $"tri {b} {h}";} class Program{    // 가장 큰 것의 자리(같으면 앞의 것). 서로 비교할 수 있는 T라면 무엇이든    static int ArgMax<T>(List<T> items) where T : IComparable<T>    {        int best = 0;        for (int i = 1; i < items.Count; i++)            if (items[i].CompareTo(items[best]) > 0) best = i;        return best;    }     static void Main()    {        Console.ReadLine();        var nums = Console.ReadLine().Trim().Split(' ').Select(int.Parse).ToList();        Console.ReadLine();        var words = Console.ReadLine().Trim().Split(' ').ToList();        int k = int.Parse(Console.ReadLine());        var shapes = new List<IShape>();        for (int i = 0; i < k; i++)        {            string[] p = Console.ReadLine().Trim().Split(' ');            int a = int.Parse(p[1]), b = int.Parse(p[2]);            shapes.Add(p[0] == "rect" ? new Rect(a, b) : new Tri(a, b));        }         Console.WriteLine(nums[ArgMax(nums)]);        Console.WriteLine(words[ArgMax(words)]);        int s = ArgMax(shapes);        Console.WriteLine($"{s + 1} {shapes[s].Describe()}");    }}