{ }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()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 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){    控制台.输出("-");}