{ }codelper
사전 찾기매개변수값 돌려주기P0147

창고 재주문 보고서

창고 장부에 물건 n가지가 적혀 있다.
첫 줄에 n이 주어지고, 다음 n줄에 물건마다 "이름 재고 기준 목표 묶음"이 빈칸 하나씩으로 나뉘어 주어진다.
그다음 줄에 출고 기록 수 m이, 다음 m줄에 출고 기록 "이름 수량"이 주어진다.
출고 기록마다 그 물건의 재고에서 수량을 뺀다.
재고가 모자라도 그대로 빼므로 재고는 음수가 될 수 있다(밀린 주문).
장부에 없는 이름의 기록은 무시한다.
기록을 모두 처리한 뒤, 재고가 기준보다 적은 물건은 묶음 단위로 다시 주문한다.
주문 묶음 수는 재고 + 묶음 수 × 묶음 ≥ 목표가 되는 가장 작은 묶음 수다.
재고가 기준과 같거나 많으면 주문하지 않는다.
묶음 수를 계산하는 부분은 (재고, 기준, 목표, 묶음)을 받아 묶음 수를 돌려주는 함수로 만든다.
첫 줄에 무시한 기록 수를 출력한다.
그다음 주문할 물건마다 "이름 묶음수"를 장부에 적힌 차례대로 한 줄씩 출력한다.
주문할 물건이 하나도 없으면 "-" 한 줄을 출력한다.

입력
1 ≤ n ≤ 100, 0 ≤ m ≤ 2000.
0 ≤ 재고 ≤ 10,000, 1 ≤ 기준 ≤ 목표 ≤ 10,000, 1 ≤ 묶음 ≤ 1000, 1 ≤ 수량 ≤ 1000(모두 정수).
이름은 영어 소문자·숫자 1 ~ 10글자이고, 장부 안에서 서로 다르다
출력
첫 줄에 무시한 기록 수, 다음 줄부터 "이름 묶음수"(장부 차례) 또는 "-"
예시 1 · stdin
4
bolt 30 20 100 25
nut 12 15 60 10
washer 5 5 40 8
gear 2 10 10 4
5
bolt 18
spring 3
nut 2
gear 7
bolt 1
stdout
1
bolt 4
nut 5
gear 4
main.py
입력(stdin)

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

$ 준비됐어요

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

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

이름으로 물건을 찾는 일과, 값 넷을 받아 하나를 돌려주는 함수가 핵심이에요.
장부에 없는 이름을 찾을 때 언어마다 결과가 달라요.
Python items[name]은 KeyError로 멈춰서 먼저 in으로 묻거나 get을 써요.
JS·TS Map.get은 undefined, Java get은 null을 돌려주고, C# items[name]은 KeyNotFoundException이라 TryGetValue를 써요.
C++ items[name]은 없는 이름을 새로 만들어 넣어서 find로 찾아야 하고, 크레이콘도 없는 열쇠를 읽으면 멈춰서 items.있나(name)을 먼저 물어요.
C에는 사전이 없어서 이름 표를 차례로 비교해요(100가지뿐이에요).
출력은 장부 차례라서 사전을 도는 차례도 중요해요.
Python dict, JS·TS Map, 크레이콘 사전은 넣은 차례를 지키지만, Java HashMap은 차례가 섞이고 C++ std::map은 사전 순으로 돌아요.
그래서 Java는 LinkedHashMap을 쓰고, C#·C++는 차례를 담은 목록을 따로 둬요(C# Dictionary의 차례는 약속되지 않아요).
묶음 수는 올림 나눗셈 (목표 − 재고 + 묶음 − 1) ÷ 묶음이에요.
함정: C·Java·C#에서 ceil((t - s) / p)라고 쓰면 정수끼리 먼저 나눠 버린 뒤라 올림이 안 돼요.
JS·TS Math.ceil((t - s) / p)는 /가 실수 나눗셈이라 맞아요.
크레이콘은 수학.몫(t - s + p - 1, p)로 써요.
또 하나: 기준과 같으면 주문하지 않으니 <예요.

Pythonmain.py · 35 줄
import sys  def packs_needed(stock, low, target, pack):    """재고가 기준보다 적으면, 목표에 닿는 가장 적은 묶음 수. 아니면 0."""    if stock >= low:        return 0    return (target - stock + pack - 1) // pack   # 올림 나눗셈  lines = sys.stdin.read().split("\n")n = int(lines[0])items = {}    # 이름 → [재고, 기준, 목표, 묶음]order = []    # 장부에 적힌 차례for line in lines[1:n + 1]:    name, *nums = line.split()    items[name] = list(map(int, nums))    order.append(name) m = int(lines[n + 1])ignored = 0for line in lines[n + 2:n + 2 + m]:    name, qty = line.split()    if name in items:        items[name][0] -= int(qty)    else:        ignored += 1 print(ignored)report = []for name in order:    p = packs_needed(*items[name])    if p > 0:        report.append(f"{name} {p}")print("\n".join(report) if report else "-")
JavaScriptmain.js · 31 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n"); // 재고가 기준보다 적으면, 목표에 닿는 가장 적은 묶음 수. 아니면 0.function packsNeeded(stock, low, target, pack) {  if (stock >= low) return 0;  return Math.ceil((target - stock) / pack);} const n = Number(lines[0]);const items = new Map(); // 이름 → { stock, low, target, pack } (Map은 넣은 차례를 지킨다)for (const line of lines.slice(1, n + 1)) {  const [name, ...nums] = line.trim().split(" ");  const [stock, low, target, pack] = nums.map(Number);  items.set(name, { stock, low, target, pack });} const m = Number(lines[n + 1]);let ignored = 0;for (const line of lines.slice(n + 2, n + 2 + m)) {  const [name, qty] = line.trim().split(" ");  const item = items.get(name); // 없으면 undefined  if (item !== undefined) item.stock -= Number(qty);  else ignored++;} const report = [];for (const [name, it] of items) {  const p = packsNeeded(it.stock, it.low, it.target, it.pack);  if (p > 0) report.push(`${name} ${p}`);}console.log(`${ignored}\n${report.length > 0 ? report.join("\n") : "-"}`);
TypeScriptmain.ts · 39 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n"); interface Item {  stock: number;  low: number;  target: number;  pack: number;} // 재고가 기준보다 적으면, 목표에 닿는 가장 적은 묶음 수. 아니면 0.function packsNeeded(stock: number, low: number, target: number, pack: number): number {  if (stock >= low) return 0;  return Math.ceil((target - stock) / pack);} const n = Number(lines[0]);const items = new Map<string, Item>(); // Map은 넣은 차례를 지킨다for (const line of lines.slice(1, n + 1)) {  const [name, ...nums] = line.trim().split(" ");  const [stock, low, target, pack] = nums.map(Number);  items.set(name, { stock, low, target, pack });} const m = Number(lines[n + 1]);let ignored = 0;for (const line of lines.slice(n + 2, n + 2 + m)) {  const [name, qty] = line.trim().split(" ");  const item = items.get(name); // Item | undefined  if (item !== undefined) item.stock -= Number(qty);  else ignored++;} const report: string[] = [];for (const [name, it] of items) {  const p = packsNeeded(it.stock, it.low, it.target, it.pack);  if (p > 0) report.push(`${name} ${p}`);}console.log(`${ignored}\n${report.length > 0 ? report.join("\n") : "-"}`);
JavaMain.java · 43 줄
import java.io.*;import java.util.*; public class Main {    // 재고가 기준보다 적으면, 목표에 닿는 가장 적은 묶음 수. 아니면 0.    static int packsNeeded(int stock, int low, int target, int pack) {        if (stock >= low) return 0;        return (target - stock + pack - 1) / pack; // 올림 나눗셈(나눌 수가 양수일 때)    }     public static void main(String[] args) throws IOException {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        int n = Integer.parseInt(br.readLine().trim());        // LinkedHashMap은 넣은 차례를 지킨다(HashMap은 차례가 섞인다)        Map<String, int[]> items = new LinkedHashMap<>();        for (int i = 0; i < n; i++) {            String[] p = br.readLine().trim().split(" ");            items.put(p[0], new int[] {                Integer.parseInt(p[1]), Integer.parseInt(p[2]), Integer.parseInt(p[3]), Integer.parseInt(p[4]) });        }        int m = Integer.parseInt(br.readLine().trim());        int ignored = 0;        for (int i = 0; i < m; i++) {            String[] p = br.readLine().trim().split(" ");            int[] it = items.get(p[0]); // 없으면 null            if (it != null) it[0] -= Integer.parseInt(p[1]);            else ignored++;        }        StringBuilder out = new StringBuilder();        out.append(ignored).append('\n');        int lines = 0;        for (Map.Entry<String, int[]> e : items.entrySet()) {            int[] it = e.getValue();            int packs = packsNeeded(it[0], it[1], it[2], it[3]);            if (packs > 0) {                out.append(e.getKey()).append(' ').append(packs).append('\n');                lines++;            }        }        if (lines == 0) out.append("-\n");        System.out.print(out);    }}
C#Main.cs · 49 줄
using System;using System.Collections.Generic;using System.Text; class Program{    // 재고가 기준보다 적으면, 목표에 닿는 가장 적은 묶음 수. 아니면 0.    static int PacksNeeded(int stock, int low, int target, int pack)    {        if (stock >= low) return 0;        return (target - stock + pack - 1) / pack; // 올림 나눗셈(나눌 수가 양수일 때)    }     static void Main()    {        int n = int.Parse(Console.ReadLine().Trim());        var items = new Dictionary<string, int[]>(); // 이름 → {재고, 기준, 목표, 묶음}        var order = new List<string>();              // 장부 차례(Dictionary의 차례는 약속되지 않는다)        for (int i = 0; i < n; i++)        {            string[] p = Console.ReadLine().Trim().Split(' ');            items[p[0]] = new[] { int.Parse(p[1]), int.Parse(p[2]), int.Parse(p[3]), int.Parse(p[4]) };            order.Add(p[0]);        }        int m = int.Parse(Console.ReadLine().Trim());        int ignored = 0;        for (int i = 0; i < m; i++)        {            string[] p = Console.ReadLine().Trim().Split(' ');            if (items.TryGetValue(p[0], out int[] it)) it[0] -= int.Parse(p[1]);            else ignored++;        }        var sb = new StringBuilder();        sb.Append(ignored).Append('\n');        int lines = 0;        foreach (string name in order)        {            int[] it = items[name];            int packs = PacksNeeded(it[0], it[1], it[2], it[3]);            if (packs > 0)            {                sb.Append(name).Append(' ').Append(packs).Append('\n');                lines++;            }        }        if (lines == 0) sb.Append("-\n");        Console.Write(sb);    }}
C++main.cpp · 47 줄
#include <iostream>#include <string>#include <unordered_map>#include <vector> struct Item {    std::string name;    int stock, low, target, pack;}; // 재고가 기준보다 적으면, 목표에 닿는 가장 적은 묶음 수. 아니면 0.int packs_needed(int stock, int low, int target, int pack) {    if (stock >= low) return 0;    return (target - stock + pack - 1) / pack; // 올림 나눗셈(나눌 수가 양수일 때)} int main() {    int n;    std::cin >> n;    std::vector<Item> items(n);                 // 장부 차례    std::unordered_map<std::string, int> where; // 이름 → 몇째 물건    for (int i = 0; i < n; i++) {        Item& it = items[i];        std::cin >> it.name >> it.stock >> it.low >> it.target >> it.pack;        where[it.name] = i;    }    int m, ignored = 0;    std::cin >> m;    for (int i = 0; i < m; i++) {        std::string name;        int qty;        std::cin >> name >> qty;        auto found = where.find(name); // [ ]로 읽으면 없는 이름이 0번으로 새로 들어간다        if (found != where.end()) items[found->second].stock -= qty;        else ignored++;    }    std::cout << ignored << "\n";    int lines = 0;    for (const Item& it : items) {        int p = packs_needed(it.stock, it.low, it.target, it.pack);        if (p > 0) {            std::cout << it.name << " " << p << "\n";            lines++;        }    }    if (lines == 0) std::cout << "-\n";}
Cmain.c · 48 줄
#include <stdio.h>#include <string.h> #define MAXN 100 static char names[MAXN][11];static int stock[MAXN], low[MAXN], target[MAXN], pack[MAXN];static int n; /* 재고가 기준보다 적으면, 목표에 닿는 가장 적은 묶음 수. 아니면 0. */static int packs_needed(int s, int lo, int t, int p) {    if (s >= lo) return 0;    return (t - s + p - 1) / p; /* 올림 나눗셈(나눌 수가 양수일 때) */} /* 이름 찾기: 몇째 물건인지, 없으면 -1 */static int find(const char *name) {    for (int i = 0; i < n; i++)        if (strcmp(names[i], name) == 0) return i;    return -1;} int main(void) {    scanf("%d", &n);    for (int i = 0; i < n; i++)        scanf("%10s %d %d %d %d", names[i], &stock[i], &low[i], &target[i], &pack[i]);    int m, ignored = 0;    scanf("%d", &m);    for (int i = 0; i < m; i++) {        char name[11];        int qty;        scanf("%10s %d", name, &qty);        int at = find(name);        if (at != -1) stock[at] -= qty;        else ignored++;    }    printf("%d\n", ignored);    int lines = 0;    for (int i = 0; i < n; i++) {        int p = packs_needed(stock[i], low[i], target[i], pack[i]);        if (p > 0) {            printf("%s %d\n", names[i], p);            lines++;        }    }    if (lines == 0) puts("-");    return 0;}
Craykonmain.cray · 50 줄
// 재고가 기준보다 적으면, 목표에 닿는 가장 적은 묶음 수. 아니면 0.묶음수(stock, low, target, pack){    만약 (stock >= low)    {        돌려주기 0;    }    돌려주기 수학.몫(target - stock + pack - 1, pack); // 올림 나눗셈} n = 콘솔.줄읽기().수로변환();items = 사전(); // 이름 → [재고, 기준, 목표, 묶음]반복 (i = 0; i < n; i++){    p = 콘솔.줄읽기().공백제거().나누기();    items[p[0]] = [p[1].수로변환(), p[2].수로변환(), p[3].수로변환(), p[4].수로변환()];} m = 콘솔.줄읽기().수로변환();ignored = 0;반복 (i = 0; i < m; i++){    p = 콘솔.줄읽기().공백제거().나누기();    만약 (items.있나(p[0]))    {        it = items[p[0]];        it[0] = it[0] - p[1].수로변환();    }    아니면    {        ignored++;    }} 콘솔.쓰기(ignored);lines = 0;각각 (name 에서 items.열쇠목록){    it = items[name];    packs = 묶음수(it[0], it[1], it[2], it[3]);    만약 (packs > 0)    {        콘솔.쓰기(name + " " + packs);        lines++;    }}만약 (lines == 0){    콘솔.쓰기("-");}