{ }codelper
標準コンテナ参照P0085

参照で受け取る在庫台帳

倉庫の在庫を品名 → 個数として std::map に入れ、n 個の命令を順に処理せよ。
命令ごとに関数を一つずつ作り、在庫を変える関数は map を参照(&)で、読むだけの関数は const 参照で受け取る。
- add 品名 k:その品を k 個足し、足した後の個数を出力する。
- get 品名:その品の個数を出力する。
ない品なら 0 を出力し、台帳に新しく書き込まない。
- use 品名 k:その品が k 個以上あれば k 個減らし、残りの個数を出力する。
残りが 0 になったらその品を台帳から消す。
k 個より少ないか、ない品なら何も変えずに -1 を出力する。
すべての命令が終わったら、台帳に残った品の数 m を出力し、続けて m 行に "品名 個数" を品名の辞書順(英小文字の文字列比較)で出力する。

入力
1 行目に n(1 ≤ n ≤ 1000)、続く n 行に命令が一つずつ。
品名は英小文字 1〜10 文字、1 ≤ k ≤ 1000
出力
命令ごとに 1 行、次に m、次に m 行の "品名 個数"
例 1 · stdin
7
add apple 5
add kiwi 2
get pear
use apple 3
use kiwi 5
use kiwi 2
get apple
stdout
5
2
0
2
-1
0
2
1
apple 2
main.py
入力(stdin)

実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

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

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

この問題は C++ だけを受け付けます。
参照(&)を選ぶことと標準コンテナ std::map を使うやり方が C++ ならではだからです(Java・C#・Python・JS はオブジェクトをいつも参照で渡すので選ぶことがなく、C には辞書がありません)。
落とし穴は三つ:① 関数が Stock stock のように & なしで受け取ると map 全体がコピーされ、関数の中で減らした個数はコピーと一緒に消えます。
② stock[name] は読むように見えますが、ない品名を 0 で新しく入れます。
get で使うと、問い合わせただけの品が最後の一覧に pear 0 のように残ります。
find で聞き、読むだけの関数を const Stock& で受け取れば [] はそもそもコンパイルできず、間違いを防いでくれます(add では 0 から足す += がかえって便利です)。
③ std::unordered_map はハッシュ順なので品名順には出ません。
std::map はキー順に回ります。
erase(it) の後はその反復子を使ってはいけないので、残りの個数を先に取り出しておきます。
Craykon なら 辞書() と 含む で同じことをしますが、参照かコピーかを選ぶことはありません。

C++main.cpp · 45 行
#include <iostream>#include <map>#include <string> using Stock = std::map<std::string, int>; // 바꾸는 함수는 참조(&)로 받는다: 복사본이 아니라 main의 stock 그 자체int add(Stock& stock, const std::string& name, int k) {    stock[name] += k;  // 없으면 0으로 만들고 더한다 — 여기서는 그게 맞다    return stock[name];} // 읽기만 하는 함수는 const 참조: 복사도 없고, stock[name]처럼 넣어 버리는 코드는 컴파일되지 않는다int get(const Stock& stock, const std::string& name) {    auto it = stock.find(name);    return it == stock.end() ? 0 : it->second;} int use(Stock& stock, const std::string& name, int k) {    auto it = stock.find(name);    if (it == stock.end() || it->second < k) return -1;    it->second -= k;    int left = it->second;    if (left == 0) stock.erase(it);  // erase 뒤에는 it를 쓰지 않는다    return left;} int main() {    int n;    std::cin >> n;    Stock stock;    for (int i = 0; i < n; i++) {        std::string cmd, name;        std::cin >> cmd >> name;        if (cmd == "get") {            std::cout << get(stock, name) << '\n';        } else {            int k;            std::cin >> k;            std::cout << (cmd == "add" ? add(stock, name, k) : use(stock, name, k)) << '\n';        }    }    std::cout << stock.size() << '\n';    for (const auto& [name, qty] : stock) std::cout << name << ' ' << qty << '\n';}