题解 | #自动售货系统#
自动售货系统
https://www.nowcoder.com/practice/cd82dc8a4727404ca5d32fcb487c50bf
字符串模拟算法。使用哈希表<string, int>和<int, int>存放商品的数量,面额的数量。
- 使用getline(cin, s, ';')可将输入按':'分割,并依次保存至s中
- 各处理函数中,如操作失败,需要return_void
- 退币函数中,需要找到最小的退币数。从大到小依次处理零钱盒中的零钱即可
- 每次操作,需要注意余额、零钱盒、结果中数值的同步
/****************************************************************************** Online C++ Compiler. Code, Compile, Run and Debug C++ program online. Write your code in this editor and press "Run" button to compile and execute it. *******************************************************************************/ #include <iostream> #include <unordered_map> #include <algorithm> #include <vector> using namespace std; /* 基本信息: 模拟一个自动售货系统,实现投币、购买、退币、查询商品和存钱和信息 售货机初始化6种商品:名称和单价给定(2,3,4,5,8,6),数量由初始化命令设置; 存钱盒4中钱币:面额(10,5,2,1),数量由初始化命令设置。 退币原则: (1)根据存钱盒内钱币信息,按总张数最少的原则退币; (2)若零钱不足导致不能退币,尽最大可能退币;(如退7,有4*2,退6) 投币:投币成功,其面额累加到投币余额;该钱币存入存钱盒,对应面额数量增加; 投币余额:当前剩余的可购买的钱币余额; 退币:根据原则退币;余额清零,同时扣除相应金额。 购买:每次一件,售货机商品-1,余额同步减少。 操作信息: 命令字与第一个参数间 用空格分隔,多条命令用分号隔开; 1. 系统初始化: r A1 ** -A2 ** ... -A6 *** 1 ** -2 ** -5 ** -10 ** (初始化数量:0-30) eg: r 6-5-4-3-2-1 4-3-2-1; S001:*** <此处不用考虑非法输入> 2. 投币:p 面额 若投入非(1,2,5,10)面额,输出E002; 投入面额大于机内1-2元硬币总额,E003; 销售完毕,E005; 投币成功,S002; 3. 购买商品: b 名称 没有该商品,E006;数量为0,E007;投币不够,E008;购买成功 4. 退币: c 无余额: E009; 5. 查询:q 0-商品信息/1-存钱盒信息 非0/1,E010 商品,优先商品数量,其次商品名称 按输入的命令进行输出,商品单价(2,3,4,5,8,6) eg: r 22-18-21-21-7-20 3-23-10-6;c;q0;p 1; b A6;c;b A5; b A1;c;q1;p 5; 思路: (1)将输入的字符串,按照';'进行分割,存入vector<string>中; 编写5个子函数,分别实现五大功能 (2)数据结构: 使用两个vector保存商品数量,存钱盒钱币数量。 使用哈希<string, string>保存E001-E010的输出信息, */ vector<int> p_price = {2, 3, 4, 5, 8, 6}; vector<string> p_name = {"A1", "A2", "A3", "A4", "A5", "A6"}; unordered_map<string, int> p_num; // 在r命令中初始化各个商品的数量。 vector<int> c_den = {1, 2, 5, 10}; unordered_map<int, int> c_num; // vector<int> c_num; vector<string> comms; // 保存各项命令 int res_balance = 0; /* 初始化商品的个数,钱币盒中各面额的个数 */ void dealR(string& s) { // 初始化R操作,保证输入的正确性! int i = 0; while (s[i] < 48 || s[i] > 57) i++; // 找到首个商品个数。 // cout << "deal " << s[i] << endl; // 读取6个商品数,注意这里的数字可能是一位数、也可能是两位数。 int cnt_p = 0; while (cnt_p < 6) { string cur_p; while (s[i] >= 48 && s[i] <= 57) { cur_p += s[i++]; } // 将保存商品的数量,修改为哈希表保存 p_num[p_name[cnt_p]] = stoi(cur_p); // p_num.push_back(stoi(cur_p)); i ++; // 跳过'-' cnt_p ++; } int cnt_c = 0; while (cnt_c < 4) { string cur_c; while (s[i] >= 48 && s[i] <= 57) { cur_c += s[i++]; } // 将保存面额数量的数据结构由int数组,修改为哈希表 c_num[c_den[cnt_c]] = stoi( cur_c); // 将面额的数量,保存在哈希表c_num中 // c_num.push_back(stoi(cur_c)); i ++; // 跳过'-' cnt_c ++; } cout << "S001:Initialization is successful" << endl; } // 处理投币 void dealP(string& s) { int i = 0; while (s[i] < 48 || s[i] > 57) i++; // 找到首个数字 // 读取6个商品数,注意这里的数字可能是一位数、也可能是两位数。 string cur_p; while (i < s.size()) { cur_p += s[i++]; } int coin = stoi(cur_p); // 当前投币的面额 if (coin == 1 || coin == 2 || coin == 5 || coin == 10) { // 投币面额大于零钱盒内零钱、且不为1/2时,投币失败。 if ((coin == 5 || coin == 10) && c_num[1] * 1 + c_num[2] * 2 < coin) { // cout << c_num[1] << " " << c_num[2] << endl; cout << "E003:Change is not enough, pay fail" << endl; return ; } // 没有剩余商品,投币失败 int flag = true; for (auto name : p_name) { if (p_num[name] != 0) flag = false; } if (flag) { cout << "E005:All the goods sold out" << endl; return; } // 余额增加、存钱盒内钱币数增加 res_balance += coin; c_num[coin] ++; cout << "S002:Pay success,balance=" + to_string(res_balance) << endl; } else { cout << "E002:Denomination error" << endl; } } // 处理退币,退币后余额为0 void dealC() { // cout << "cur coin is " << res_balance << " " << c_num[1] << endl; if (res_balance == 0) cout << "E009:Work failure" << endl;; // 按退币原则找零 if (res_balance > 0) { /* 给定一个面额,以及1,2,5,10面额的数量 得到最少的张数,以最大限度达到面额__背包问题*/ unordered_map<int, int> c_back; vector<int> c_sort = {10, 5, 2, 1}; while (res_balance > 0) { int cur_den = 0; // 可以退币的最大面额。 for (auto c : c_sort) { if (res_balance >= c && c_num[c] > 0) { cur_den = c; break; } } // 存钱盒内零钱不够。 if (cur_den == 0) break; // 余额减少、存钱盒钱币减少,并记录输出信息 res_balance -= cur_den; c_num[cur_den] --; c_back[cur_den] ++; } // 退币后,余额清零 res_balance = 0; for (auto c : c_den) { cout << to_string(c) + " yuan coin number=" + to_string(c_back[c]) << endl; } } } // 购买商品 void dealB(string& s) { string b_name; for (int i = 2; i < s.size(); i++) b_name += s[i]; auto it = find(p_name.begin(), p_name.end(), b_name); bool flag = it == p_name.end(); if (flag) { cout << "E006:Goods does not exist" << endl; return; } if (p_num[b_name] == 0) { cout << "E007:The goods sold out" << endl; return; } int index = it - p_name.begin(); if (res_balance < p_price[index]) { cout << "E008:Lack of balance" << endl; return; } // 成功购买 res_balance -= p_price[index]; p_num[b_name]--; cout << "S003:Buy success,balance=" + to_string(res_balance) << endl; } // 查询 void dealQ(string& s) { // 查询失败 if (s.size() != 3) { cout << "E010:Parameter error" << endl; return; } if (s[1] != ' ' || (s[2] != 0 && s[2] != 1)) { cout << "E010:Parameter error" << endl; return; } // 查询商品信息,输出名称,单价,数量 if (s[2] == 0) { for (int i = 0 ; i < p_name.size(); i++) { cout << p_name[i] << " " << p_price[i] << " " << p_num[p_name[i]] << endl; } } // 查询零钱盒信息 if (s[2] == 1) { for (int i = 0 ; i < c_den.size(); i++) { cout << to_string(c_den[i]) << " yuan coin number=" << to_string( c_num[c_den[i]]) << endl; } } } int main() { string input; while (getline(cin, input, ';')) { comms.push_back(input); // cout << input << endl; } // cout << "输入大小:" << comms.size() << endl; // 遍历所有的指令 for (auto cur : comms) { // cout << cur << endl; if (cur[0] == 'r') { dealR(cur); } if (cur[0] == 'p') dealP(cur); if (cur[0] == 'c') dealC(); if (cur[0] == 'q') dealQ(cur); if (cur[0] == 'b') dealB(cur); } /* // test the result of dearR func. for(auto p : p_price){ cout << p << " "; } cout << endl; for(auto p : p_num){ cout << p.first << " " << p.second; cout << endl; } cout << endl; for(auto c : c_num){ cout << c.first << c.second << " "; // 默认大根堆存储 } cout << endl; */ return 0; }