题解 | #自动售货系统#

自动售货系统

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;
}




全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务