{ }codelper
标准容器引用P0085

按引用传递的库存账本

把仓库库存按 物品名 → 数量 存进 std::map,依次处理 n 条命令。
每种命令写一个函数;会修改库存的函数用引用(&)接收 map,只读取的函数用 const 引用接收。
- add 名称 k:该物品加 k 个,输出加完后的数量。
- get 名称:输出该物品的数量。
若没有该物品则输出 0,并且不要把它新记入账本。
- use 名称 k:若该物品至少有 k 个,减去 k 个并输出剩余数量;剩余为 0 时把该物品从账本删除。
若不足 k 个或没有该物品,则什么都不改,输出 -1。
所有命令处理完后,输出账本中剩下的物品数 m,接着 m 行按名称的字典序(小写字母串比较)输出 "名称 数量"。

输入
第一行 n(1 ≤ n ≤ 1000),接下来 n 行每行一条命令。
名称为 1~10 个小写英文字母,1 ≤ k ≤ 1000
输出
每条命令一行,然后是 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';}