{ }codelper
辞書の検索引数戻り値P0147

倉庫の再注文レポート

倉庫の台帳に n 種類の品物が書かれている。
一行目に n が与えられ、続く n 行に品物ごとの "名前 在庫 基準 目標 入数" が空白一つずつで区切られて与えられる(入数は 1 箱に入る個数)。
その次の行に出庫記録の数 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()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。

ほかの言語では?言語別の解答を見る · 8 言語の解答

名前で品物を探すことと、値を四つ受け取って一つを返す関数が中心です。
台帳にない名前を探したときの結果が言語によって違います。
Python の items[name] は KeyError で止まるので、先に in で確かめるか get を使います。
JS・TS の Map.get は undefined、Java の get は null を返し、C# の items[name] は KeyNotFoundException なので TryGetValue を使います。
C++ の items[name] はない名前を新しく作って入れるので find で探し、Craykon もないキーを読むと止まるので先に items.含む(name)(韓国語 items.있나(name))を確かめます。
C には辞書がないので名前の表を順に比べます(100 種類だけです)。
出力は台帳の順なので、辞書を回る順番も大事です。
Python の dict、JS・TS の Map、Craykon の 辞書(韓国語 사전)は入れた順を守りますが、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) は / が実数の割り算なので正しいです。
Craykon は 数学.商(t - s + p - 1, 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){    コンソール.書く("-");}