회사의 직원은 세 종류이고, 한 달 동안의 기록으로 월급을 계산한다.
모든 직원은 이름과 함께, 이번 달에 일한 시간의 합과 판매 금액의 합을 기록해 둔다.
기본 직원(staff)의 월급은 기본급이다.
시급 직원(hourly)의 월급은 160시간까지는 시간마다 시급, 160시간을 넘은 시간은 시간마다 시급의 2배다.
판매 직원(sales)의 월급은 기본급에 수당을 더한 것이고, 수당은 판매 금액의 합에 비율 p를 곱해 100으로 나눈 값의 소수 부분을 버린 정수다.
일한 시간과 판매 금액은 어느 종류의 직원에게나 기록될 수 있지만, 월급 계산에는 위에 적힌 것만 쓴다.
첫 줄에 직원 수 n, 다음 n줄에 직원이 "staff 이름 기본급", "hourly 이름 시급", "sales 이름 기본급 p" 중 하나로 주어진다.
그다음 줄에 기록 수 q, 다음 q줄에 기록이 "work 이름 시간" 또는 "sell 이름 금액"으로 주어진다.
직원마다 "이름 월급"을 입력에 나온 차례대로 한 줄씩 출력하고, 마지막 줄에 "total 월급의합"을 출력하라.
기본 직원을 기반 클래스 Employee로 만들고, 시급 직원과 판매 직원을 그 하위 클래스로 만들어 월급 메서드 pay를 덮어쓰자(override).
직원들을 Employee 목록 하나에 담고, 종류를 묻지 않고 pay를 불러 계산해 보자.
입력
1 ≤ n ≤ 100, 1 ≤ q ≤ 2,000. 이름은 영어 소문자·숫자 1 ~ 10글자이고 서로 다르다. 0 ≤ 기본급 ≤ 1,000,000, 1 ≤ 시급 ≤ 10,000, 0 ≤ p ≤ 30, 기록의 시간은 1 이상 12 이하, 금액은 1 이상 10,000 이하의 정수다. 기록의 이름은 모두 있는 직원이다
출력
n+1줄: 직원마다 "이름 월급", 마지막 줄에 "total 합"
예시 1 · stdin
3
staff ann 3000
hourly bob 10
sales cy 1000 5
5
work bob 12
sell cy 150
work ann 8
sell cy 99
sell ann 500
stdout
ann 3000
bob 120
cy 1012
total 4132
main.py
오류 목록00F8 ↓ · ⇧F8 ↑
입력(stdin)
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 6개 언어 풀이
이 문제는 클래스 상속이 있는 Python·JavaScript·TypeScript·Java·C#·C++만 받아요(C에는 클래스가 없고, 크레이콘은 아직 클래스를 만들 수 없어요). 하위 클래스를 만드는 문법은 Python class Hourly(Employee), JS·TS·Java class Hourly extends Employee, C# class Hourly : Employee, C++ class Hourly : public Employee이고, 판매 직원은 기반 클래스의 계산을 super().pay()(Python)·super.pay()(JS·TS·Java)·base.Pay()(C#)·Employee::pay()(C++)로 불러 수당만 더해요. 크게 다른 건 덮어쓰기가 언제 저절로 되느냐예요. Python·JS·TS·Java는 같은 이름의 메서드를 다시 쓰면 늘 덮어써져요(TypeScript는 override를 붙이면 기반에 그 메서드가 없을 때 타입 오류가 나고, noImplicitOverride를 켜면 override를 빠뜨린 것도 잡아요). C#은 기반에 virtual, 하위에 override가 모두 있어야 하고, C++도 기반의 virtual이 있어야 Employee*로 부를 때 진짜 클래스의 pay가 불려요. 함정 다섯: ① C++에서 virtual을 빠뜨리면 컴파일은 되지만 line() 안의 pay()가 늘 Employee::pay라서 시급 직원이 0원이 돼요. ② C++에서 std::vector<Employee>처럼 값으로 담으면 하위 객체가 잘려(slicing) 기반 부분만 남아요. std::vector<std::unique_ptr<Employee>>로 담아요. ③ C#에서 override를 빠뜨리면 경고(CS0114)만 나고 새 메서드로 숨겨져서, Employee로 부르면 기반의 Pay가 불려요. ④ Java는 @Override가 없으면 Pay()처럼 철자를 틀린 메서드가 새 메서드로 조용히 생겨요. @Override를 붙이면 컴파일 오류로 잡혀요. ⑤ JS·TS의 /는 소수까지 나눠서 수당이 12.45처럼 나와요. Math.floor로 버려요(Python은 //, Java·C#·C++의 int 나눗셈은 0 이상이면 저절로 버려져요). 덤으로 Python에서 sales = []를 __init__이 아니라 클래스 몸통에 쓰면 모든 직원이 한 목록을 함께 써요.
Pythonmain.py · 70 줄
import sysclass Employee: """기본 직원: 기본급만 받는다. 일한 시간과 판매 기록은 모든 직원이 가진다.""" def __init__(self, name, base): self.name = name self.base = base self.hours = 0 self.sales = [] # 판매 금액 기록(인스턴스마다 따로 만든다) def work(self, h): self.hours += h def sell(self, amount): self.sales.append(amount) def pay(self): return self.base def line(self): return f"{self.name} {self.pay()}" # 어느 클래스의 pay가 불릴지는 실행 중에 정해진다class Hourly(Employee): def __init__(self, name, rate): super().__init__(name, 0) self.rate = rate def pay(self): over = max(0, self.hours - 160) return self.rate * (self.hours - over) + 2 * self.rate * overclass Sales(Employee): def __init__(self, name, base, pct): super().__init__(name, base) self.pct = pct def pay(self): return super().pay() + sum(self.sales) * self.pct // 100lines = sys.stdin.read().split("\n")n = int(lines[0])staff = []by_name = {}for i in range(1, n + 1): p = lines[i].split() if p[0] == "staff": e = Employee(p[1], int(p[2])) elif p[0] == "hourly": e = Hourly(p[1], int(p[2])) else: e = Sales(p[1], int(p[2]), int(p[3])) staff.append(e) by_name[e.name] = eq = int(lines[n + 1])for i in range(n + 2, n + 2 + q): cmd, name, x = lines[i].split() if cmd == "work": by_name[name].work(int(x)) else: by_name[name].sell(int(x))for e in staff: print(e.line())print("total", sum(e.pay() for e in staff))
JavaScriptmain.js · 68 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");// 기본 직원: 기본급만 받는다. 일한 시간과 판매 합계는 모든 직원이 가진다class Employee { constructor(name, base) { this.name = name; this.base = base; this.hours = 0; this.sold = 0; } work(h) { this.hours += h; } sell(amount) { this.sold += amount; } pay() { return this.base; } line() { return `${this.name} ${this.pay()}`; // 객체의 진짜 클래스의 pay가 불린다 }}class Hourly extends Employee { constructor(name, rate) { super(name, 0); this.rate = rate; } pay() { const over = Math.max(0, this.hours - 160); return this.rate * (this.hours - over) + 2 * this.rate * over; }}class Sales extends Employee { constructor(name, base, pct) { super(name, base); this.pct = pct; } pay() { return super.pay() + Math.floor((this.sold * this.pct) / 100); // JS의 /는 소수까지 나눈다 }}const n = Number(lines[0]);const staff = [];const byName = new Map();for (let i = 1; i <= n; i++) { const p = lines[i].trim().split(" "); let e; if (p[0] === "staff") e = new Employee(p[1], Number(p[2])); else if (p[0] === "hourly") e = new Hourly(p[1], Number(p[2])); else e = new Sales(p[1], Number(p[2]), Number(p[3])); staff.push(e); byName.set(e.name, e);}const q = Number(lines[n + 1]);for (let i = n + 2; i < n + 2 + q; i++) { const [cmd, name, x] = lines[i].trim().split(" "); if (cmd === "work") byName.get(name).work(Number(x)); else byName.get(name).sell(Number(x));}const out = staff.map((e) => e.line());out.push(`total ${staff.reduce((s, e) => s + e.pay(), 0)}`);console.log(out.join("\n"));
TypeScriptmain.ts · 72 줄
import { readFileSync } from "node:fs";// 기본 직원: 기본급만 받는다. 일한 시간과 판매 합계는 모든 직원이 가진다class Employee { protected hours = 0; protected sold = 0; constructor(readonly name: string, protected readonly base: number) {} work(h: number): void { this.hours += h; } sell(amount: number): void { this.sold += amount; } pay(): number { return this.base; } line(): string { return `${this.name} ${this.pay()}`; // 객체의 진짜 클래스의 pay가 불린다 }}class Hourly extends Employee { constructor(name: string, private readonly rate: number) { super(name, 0); } override pay(): number { const over = Math.max(0, this.hours - 160); return this.rate * (this.hours - over) + 2 * this.rate * over; }}class Sales extends Employee { constructor(name: string, base: number, private readonly pct: number) { super(name, base); } override pay(): number { return super.pay() + Math.floor((this.sold * this.pct) / 100); // number의 /는 소수까지 나눈다 }}const lines: string[] = readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);const staff: Employee[] = [];const byName = new Map<string, Employee>();for (let i = 1; i <= n; i++) { const p: string[] = lines[i].trim().split(" "); let e: Employee; if (p[0] === "staff") e = new Employee(p[1], Number(p[2])); else if (p[0] === "hourly") e = new Hourly(p[1], Number(p[2])); else e = new Sales(p[1], Number(p[2]), Number(p[3])); staff.push(e); byName.set(e.name, e);}const q = Number(lines[n + 1]);for (let i = n + 2; i < n + 2 + q; i++) { const [cmd, name, x] = lines[i].trim().split(" "); const e = byName.get(name)!; if (cmd === "work") e.work(Number(x)); else e.sell(Number(x));}const out: string[] = staff.map((e) => e.line());out.push(`total ${staff.reduce((s, e) => s + e.pay(), 0)}`);console.log(out.join("\n"));
JavaMain.java · 72 줄
import java.io.*;import java.util.*;public class Main { // 기본 직원: 기본급만 받는다. 일한 시간과 판매 합계는 모든 직원이 가진다 static class Employee { final String name; final int base; int hours = 0, sold = 0; Employee(String name, int base) { this.name = name; this.base = base; } void work(int h) { hours += h; } void sell(int amount) { sold += amount; } int pay() { return base; } String line() { return name + " " + pay(); } // 객체의 진짜 클래스의 pay가 불린다 } static class Hourly extends Employee { final int rate; Hourly(String name, int rate) { super(name, 0); this.rate = rate; } @Override int pay() { int over = Math.max(0, hours - 160); return rate * (hours - over) + 2 * rate * over; } } static class Sales extends Employee { final int pct; Sales(String name, int base, int pct) { super(name, base); this.pct = pct; } @Override int pay() { return super.pay() + sold * pct / 100; } } public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int n = Integer.parseInt(br.readLine().trim()); List<Employee> staff = new ArrayList<>(); Map<String, Employee> byName = new HashMap<>(); for (int i = 0; i < n; i++) { String[] p = br.readLine().trim().split(" "); Employee e = switch (p[0]) { case "staff" -> new Employee(p[1], Integer.parseInt(p[2])); case "hourly" -> new Hourly(p[1], Integer.parseInt(p[2])); default -> new Sales(p[1], Integer.parseInt(p[2]), Integer.parseInt(p[3])); }; staff.add(e); byName.put(e.name, e); } int q = Integer.parseInt(br.readLine().trim()); for (int i = 0; i < q; i++) { String[] p = br.readLine().trim().split(" "); Employee e = byName.get(p[1]); if (p[0].equals("work")) e.work(Integer.parseInt(p[2])); else e.sell(Integer.parseInt(p[2])); } StringBuilder sb = new StringBuilder(); int total = 0; for (Employee e : staff) { sb.append(e.line()).append('\n'); total += e.pay(); } sb.append("total ").append(total).append('\n'); System.out.print(sb); }}
C#Main.cs · 78 줄
using System;using System.Collections.Generic;using System.Linq;using System.Text;// 기본 직원: 기본급만 받는다. 일한 시간과 판매 합계는 모든 직원이 가진다class Employee{ public string Name { get; } protected int Base { get; } protected int Hours { get; private set; } protected int Sold { get; private set; } public Employee(string name, int baseSalary) { Name = name; Base = baseSalary; } public void Work(int h) => Hours += h; public void Sell(int amount) => Sold += amount; // virtual이어야 하위 클래스가 override할 수 있다 public virtual int Pay() => Base; public string Line() => $"{Name} {Pay()}"; // 객체의 진짜 클래스의 Pay가 불린다}class Hourly : Employee{ private readonly int rate; public Hourly(string name, int rate) : base(name, 0) { this.rate = rate; } public override int Pay() { int over = Math.Max(0, Hours - 160); return rate * (Hours - over) + 2 * rate * over; }}class Sales : Employee{ private readonly int pct; public Sales(string name, int baseSalary, int pct) : base(name, baseSalary) { this.pct = pct; } public override int Pay() => base.Pay() + Sold * pct / 100;}class Program{ static void Main() { int n = int.Parse(Console.ReadLine()!.Trim()); var staff = new List<Employee>(); var byName = new Dictionary<string, Employee>(); for (int i = 0; i < n; i++) { var p = Console.ReadLine()!.Trim().Split(' '); Employee e = p[0] switch { "staff" => new Employee(p[1], int.Parse(p[2])), "hourly" => new Hourly(p[1], int.Parse(p[2])), _ => new Sales(p[1], int.Parse(p[2]), int.Parse(p[3])), }; staff.Add(e); byName[e.Name] = e; } int q = int.Parse(Console.ReadLine()!.Trim()); for (int i = 0; i < q; i++) { var p = Console.ReadLine()!.Trim().Split(' '); if (p[0] == "work") byName[p[1]].Work(int.Parse(p[2])); else byName[p[1]].Sell(int.Parse(p[2])); } var sb = new StringBuilder(); foreach (var e in staff) sb.Append(e.Line()).Append('\n'); sb.Append("total ").Append(staff.Sum(e => e.Pay())).Append('\n'); Console.Write(sb); }}
C++main.cpp · 87 줄
#include <algorithm>#include <iostream>#include <memory>#include <string>#include <unordered_map>#include <vector>// 기본 직원: 기본급만 받는다. 일한 시간과 판매 합계는 모든 직원이 가진다class Employee {public: Employee(std::string name, int base) : name_(std::move(name)), base_(base) {} virtual ~Employee() = default; // 기반 클래스 포인터로 지울 때 하위 소멸자도 불리게 const std::string &name() const { return name_; } void work(int h) { hours_ += h; } void sell(int amount) { sold_ += amount; } // virtual이어야 Employee* 로 불러도 객체의 진짜 클래스의 pay가 불린다 virtual int pay() const { return base_; } std::string line() const { return name_ + " " + std::to_string(pay()); }protected: std::string name_; int base_; int hours_ = 0, sold_ = 0;};class Hourly : public Employee {public: Hourly(std::string name, int rate) : Employee(std::move(name), 0), rate_(rate) {} int pay() const override { int over = std::max(0, hours_ - 160); return rate_ * (hours_ - over) + 2 * rate_ * over; }private: int rate_;};class Sales : public Employee {public: Sales(std::string name, int base, int pct) : Employee(std::move(name), base), pct_(pct) {} int pay() const override { return Employee::pay() + sold_ * pct_ / 100; }private: int pct_;};int main() { std::ios::sync_with_stdio(false); int n; std::cin >> n; // 객체를 값으로 담으면(vector<Employee>) 하위 부분이 잘려 나간다: 포인터로 담는다 std::vector<std::unique_ptr<Employee>> staff; std::unordered_map<std::string, Employee *> byName; for (int i = 0; i < n; i++) { std::string kind, name; int base; std::cin >> kind >> name >> base; if (kind == "staff") staff.push_back(std::make_unique<Employee>(name, base)); else if (kind == "hourly") staff.push_back(std::make_unique<Hourly>(name, base)); else { int pct; std::cin >> pct; staff.push_back(std::make_unique<Sales>(name, base, pct)); } byName[name] = staff.back().get(); } int q; std::cin >> q; for (int i = 0; i < q; i++) { std::string cmd, name; int x; std::cin >> cmd >> name >> x; if (cmd == "work") byName[name]->work(x); else byName[name]->sell(x); } int total = 0; for (const auto &e : staff) { std::cout << e->line() << '\n'; total += e->pay(); } std::cout << "total " << total << '\n';}