题目的主要信息:

  • 实现一个简单的自动售货系统,实现投币、购买商品、退币、查询库存商品及存钱盒信息的功能
  • 一共售卖6种商品,商品名称和售价如下,零钱盒中记录1元、2元、5元、10元4种零钱的数量。
商品名称 单价
A1 2
A2 3
A3 4
A4 5
A5 8
A6 6

其他信息太多了,在解题的时候一起说,不在此赘述

方法一:直接判断

具体做法:

需要实现5个功能,我们分成5个函数,输入的命令之间通过分号连接,我们可以通过字符串流输入获取分号间的子串,组成一个数组,然后遍历子串数组就是遍历每条命令,命令开头字母对应相应的功能及函数。

  • money表示投入的币有多少钱
  • goods表示商品数量
  • price表示每件商品价格
  • coins表示零钱盒中各类零钱的数量

第一个功能,初始化

命令后面两串数字表示分别初始化商品数量和零钱数量,数字之间用-间隔,商品和零钱之间用空格间隔。我们可以截取去掉前两位,遍历后续数字,遇到到数字字符就转化为数字加入数字中,遇到-符号就进入下一个商品,遇到空格则变成开始初始化零钱数量,和前面商品类似,我们可以用一个bool型flag变量来区分。

同时初始化的时候要把money投入的钱置为0,初始化成功之后输出。

第二个功能,投币

只能投入1元、2元、5元、10元四种币种,一次只能投一张钱币,因此截取数字后先检查是否是这四种,然后检查存钱盒中1元和2元面额钱币总额小于本次投入的钱币面额,再检查自动售货机中商品全部销售完毕,最后才是投币成功,零钱盒中数量增加,已投币数量money也增加。优先级的顺序已经用判断语句的先后顺序考虑了,下同

第三个功能,购买

根据输入的命令,检查商品名称是否在A1到A6这个范围内,再检查所购买的商品是否数量为0,再检查已投币money是否小于商品价格,最后才能购买成功,一条命令只能买一条,购买成功需要将money和库存一起减少。

第四个功能,退币

退币有两个条件:

- 根据系统存钱盒内钱币的 信息 ,按钱币总张数最少的原则进行退币
- 如果因零钱不足导致不能退币,则尽最大可能退币,以减少用户损失

因此我们准备abcd代表要退的四种面额的数量,应该先从10元的开始退,尽可能多的拿高面值的币,然后剩余的钱要么是零碎的要么是高面值不够了剩余的才开始用低面值的钱,退钱后需要减少已投币money的数量,同时减少零钱盒中相应钱币的数量。

第五个功能,查询

输入命令查询0,是查询商品信息,查询1是查询零钱盒信息,其余的都是非法命令。

对于商品信息,我们使用vector<pair<pair<string, int>, int>>数组来记录商品名称、价格及数量,然后重载比较信息,在数量不同时以数量降序,在数量相同时以名称升序来排序,最后输出。

对于零钱信息就直接输出这四项即可。

alt

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<sstream>
using namespace std;

int price[6] = {2, 3, 4, 5, 8, 6}; // 商品价格
int money = 0; //投入的钱

vector<string> split(string str, const char c){ //通过字符c分割字符串
    vector<string> res;
    istringstream iss(str); // 字符串流输入
    string temp = "";
    while(getline(iss, temp, c)) //根据流输入分割
        res.push_back(temp);
    return res;
}

void init(vector<int>& a, vector<int>& b, string& s){ //初始化函数
    money = 0; //初始化投入的钱
    s = s.substr(2, s.length() - 2); //去掉前面的r和空格
    a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = 0;
    b[0] = b[1] = b[2] = b[3] = 0;
    int i = 0;
    bool flag = false; //判别是前面部分商品价格还是后面部分零钱盒
    for(auto c: s){
        if(isdigit(c) && !flag) //数字且是价格
            a[i] = a[i] * 10 + (c -' 0'); //根据字符计算数字
        else if(isdigit(c) && flag) //数字且是零钱
            b[i] = b[i] * 10 + (c - '0'); //根据字符计算数字
        else if(c == ' '){ //遇到空格换成零钱
            flag = true;
            i = 0;
        }
        else if(c == '-') //遇到-后移一位商品或零钱
            i++;
    }
    cout << "S001:Initialization is successful" << endl;
}

void pay(vector<int>& a, vector<int>& b, string& s){ //投币函数
    int num = 0;
    for(auto &c: s) 
        if(isdigit(c)) //只计算数字部分
            num = num * 10 + (c - '0'); //一次只投一张
    if(num == 1 || num == 2 || num == 5 || num == 10){ //投入合法的币种
        if(num > 2 && num > (b[0] + b[1] * 2)) //存钱盒中1元和2元面额钱币总额小于本次投入的钱币面额
            cout << "E003:Change is not enough, pay fail" << endl;
        else if((a[0] || a[1] || a[2] || a[3] || a[4] || a[5]) == 0) //商品全部为0
            cout << "E005:All the goods sold out" << endl;
        else{ //零钱盒中钱数增加
            if(num == 1 || num == 2) 
                b[num-1]++;
            else if(num == 5) 
                b[2]++;
            else b[3]++;
            money += num; //投入的总钱数增加
            cout << "S002:Pay success,balance=" << money << endl;
        }
    }
    else //不合法币种
        cout << "E002:Denomination error" << endl;
}

void buy(vector<int>& a, vector<int>& b, string& s){ //购买函数
    //检查命令是否是4位,第三位是否为A,第四位是否数字1-6
    if(s.length() == 4 && (s[2] == 'A') && (s[3] - '0' < 7) && isdigit(s[3]) && (s[3] != '0')){
        if(a[s[3] - '1'] == 0) //该商品的售罄
            cout << "E007:The goods sold out" << endl;
        else if(price[s[3] - '1'] > money) //该商品价格大于投入的钱
            cout << "E008:Lack of balance" << endl;
        else{ //成功购买
            money -= price[s[3] - '1']; //投入的钱要减去买的商品
            a[s[3] - '1']--;
            cout << "S003:Buy success,balance=" << money << endl;
        }
    }
    else //输入命令不合法,商品不存在
        cout << "E006:Goods does not exist" << endl;
}

void back(vector<int>& coins){//退币函数
    int a = 0, b = 0, c = 0, d = 0; //四个币种
    if(money == 0) //投入的没有钱了,不用退
        cout << "E009:Work failure" << endl;
    else{
        d = money / 10; //优先退大币额的数量
        if(d <= coins[3]){ //10块的钱够退
            money = money % 10;
            coins[3] -= d;
        }
        else{ //10块的钱不够退
            d = coins[3]; //全部退完
            coins[3] = 0;
            money -= d * 10; //剩余要退的
        }
        c = money / 5; //再计算要退的5块钱的数量
        if(c <= coins[2]){ //5块的钱够退
            money = money % 5;
            coins[2] -= c;
        }
        else{ //5块的钱不够退
            c = coins[2]; //全部退完
            coins[2] = 0;
            money -= d * 5; //剩余要退的
        }
        b = money / 2; //再计算要退的2块钱的数量
        if(b <= coins[1]){ //2块的钱够退
            money = money % 2;
            coins[1] -= b;
        }
        else{ //2块的钱不够退
            b = coins[1]; //全部退完
            coins[1] = 0;
            money -= d * 2; //剩余要退的
        }
        a = money;  //再计算要退的1块钱的数量
        if(a <= coins[0]){ //1块的钱够退
            coins[0] -= a;
            money = 0;
        }
        else{ //1块的钱不够退
            coins[0] = 0;
            money -= a;
        }
        cout << "1 yuan coin number=" << a << endl << "2 yuan coin number=" << b << endl << "5 yuan coin number=" << c << endl << "10 yuan coin number=" << d << endl;
    }
}

bool cmp(pair<pair<string, int>, int>& a, pair<pair<string, int>, int>& b){ //重载比较
    if(a.second != a.second) //优先比较商品数量
        return a.second > b.second;
    else //再比较商品名字
        return a.first.first < b.first.first;
}
void query(vector<int>& a, vector<int>& b, string& s){ //查询函数
    if(s[1] == ' ' && s.length() == 3){ //检查查询命令的合法性
        if(s[2] == 0){ //类别为0
            vector<pair<pair<string, int>, int> > temp;
            for(int i = 0; i < 6; i++) //商品信息入vector方便排序输出
                temp.push_back(make_pair(make_pair("A" + char(i + 1), price[i]), a[i]));
            sort(temp.begin(), temp.end(), cmp); //按照重载后的比较排序
            for(int i = 0; i < 6; i++) //输出
                cout << temp[i].first.first << " " << temp[i].first.second << " " << temp[i].second << endl;
        }
        else if(s[2] == 1){ //类别为1
            cout << "1 yuan coin number=" << b[0] << endl
                 << "2 yuan coin number=" << b[1] << endl
                 << "5 yuan coin number=" << b[2] << endl
                 << "10 yuan coin number=" << b[3] << endl;
        }
        else
            cout << "E010:Parameter error" << endl;
    }
    else
        cout << "E010:Parameter error" << endl;
}
    
int main(){
    string s;
    vector<int> goods(6, 0);
    vector<int> coins(4, 0);
    while(getline(cin, s)){
        vector<string> orders = split(s, ';');
        for(auto c: orders){
            switch(c[0]){
                case 'r': //初始化
                    init(goods, coins, c);
                    break;
                case 'p': //投币
                    pay(goods, coins, c);
                    break;
                case 'b': //购买商品
                    buy(goods, coins, c);
                    break;
                case 'c': //退币
                    back(coins);
                    break;
                case 'q': //查询
                    query(goods, coins, c);
                    break;
            }
        }
    }
    return 0;
}

复杂度分析:

  • 时间复杂度:O(n)O(n),其中nn为每次输入的命令的条数,所有操作都是常数时间完成的
  • 空间复杂度:O(1)O(1),常数级空间

方法二:类封装

具体做法:

我们可以将上述的price、money、goods、coins等变量封装为一个类的成员变量,设置为private,不可被被外直接访问,然后五种功能对应的五个函数则作为成员函数,可以访问上述成员变量,由此组成了一个Vending类,操作更封装,其余同方法一。

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<sstream>
using namespace std;

bool cmp(pair<pair<string, int>, int>& a, pair<pair<string, int>, int>& b){ //重载比较
    if(a.second != a.second) //优先比较商品数量
        return a.second > b.second;
    else //再比较商品名字
        return a.first.first < b.first.first;
}

class Vending{
private:
    vector<int> price = {2, 3, 4, 5, 8, 6};  // 商品价格
    int money = 0;
    vector<int> goods; //商品数量
    vector<int> coins; //零钱数量
    
public:
    void init(string& s){ //初始化函数
        money = 0; //初始化投入的钱
        s = s.substr(2, s.length() - 2); //去掉前面的r和空格
        goods.resize(6);
        coins.resize(4);
        goods[0] = goods[1] = goods[2] = goods[3] = goods[4] = goods[5] = 0;
        coins[0] = coins[1] = coins[2] = coins[3] = 0;
        int i = 0;
        bool flag = false; //判别是前面部分商品价格还是后面部分零钱盒
        for(auto c: s){
            if(isdigit(c) && !flag) //数字且是价格
                goods[i] = goods[i] * 10 + (c -' 0'); //根据字符计算数字
            else if(isdigit(c) && flag) //数字且是零钱
                coins[i] = coins[i] * 10 + (c - '0'); //根据字符计算数字
            else if(c == ' '){ //遇到空格换成零钱
                flag = true;
                i = 0;
            }
            else if(c == '-') //遇到-后移一位商品或零钱
                i++;
        }
        cout << "S001:Initialization is successful" << endl;
    }
    
    void pay(string& s){ //投币函数
        int num = 0;
        for(auto &c: s) 
            if(isdigit(c)) //只计算数字部分
                num = num * 10 + (c - '0'); //一次只投一张
        if(num == 1 || num == 2 || num == 5 || num == 10){ //投入合法的币种
            if(num > 2 && num > (coins[0] + coins[1] * 2)) //存钱盒中1元和2元面额钱币总额小于本次投入的钱币面额
                cout << "E003:Change is not enough, pay fail" << endl;
            else if((goods[0] || goods[1] || goods[2] || goods[3] || goods[4] || goods[5]) == 0) //商品全部为0
                cout << "E005:All the goods sold out" << endl;
            else{ //零钱盒中钱数增加
                if(num == 1 || num == 2) 
                    coins[num-1]++;
                else if(num == 5) 
                    coins[2]++;
                else coins[3]++;
                money += num; //投入的总钱数增加
                cout << "S002:Pay success,balance=" << money << endl;
            }
        }
        else //不合法币种
            cout << "E002:Denomination error" << endl;
    }
    
    void buy(string& s){ //购买函数
        //检查命令是否是4位,第三位是否为A,第四位是否数字1-6
        if(s.length() == 4 && (s[2] == 'A') && (s[3] - '0' < 7) && isdigit(s[3]) && (s[3] != '0')){
            if(goods[s[3] - '1'] == 0) //该商品的售罄
                cout << "E007:The goods sold out" << endl;
            else if(price[s[3] - '1'] > money) //该商品价格大于投入的钱
                cout << "E008:Lack of balance" << endl;
            else{ //成功购买
                money -= price[s[3] - '1']; //投入的钱要减去买的商品
                goods[s[3] - '1']--;
                cout << "S003:Buy success,balance=" << money << endl;
            }
        }
        else //输入命令不合法,商品不存在
            cout << "E006:Goods does not exist" << endl;
    }
    
    void back(){//退币函数
        int a = 0, b = 0, c = 0, d = 0; //四个币种
        if(money == 0) //投入的没有钱了,不用退
            cout << "E009:Work failure" << endl;
        else{
            d = money / 10; //优先退大币额的数量
            if(d <= coins[3]){ //10块的钱够退
                money = money % 10;
                coins[3] -= d;
            }
            else{ //10块的钱不够退
                d = coins[3]; //全部退完
                coins[3] = 0;
                money -= d * 10; //剩余要退的
            }
            c = money / 5; //再计算要退的5块钱的数量
            if(c <= coins[2]){ //5块的钱够退
                money = money % 5;
                coins[2] -= c;
            }
            else{ //5块的钱不够退
                c = coins[2]; //全部退完
                coins[2] = 0;
                money -= d * 5; //剩余要退的
            }
            b = money / 2; //再计算要退的2块钱的数量
            if(b <= coins[1]){ //2块的钱够退
                money = money % 2;
                coins[1] -= b;
            }
            else{ //2块的钱不够退
                b = coins[1]; //全部退完
                coins[1] = 0;
                money -= d * 2; //剩余要退的
            }
            a = money;  //再计算要退的1块钱的数量
            if(a <= coins[0]){ //1块的钱够退
                coins[0] -= a;
                money = 0;
            }
            else{ //1块的钱不够退
                coins[0] = 0;
                money -= a;
            }
            cout << "1 yuan coin number=" << a << endl << "2 yuan coin number=" << b << endl << "5 yuan coin number=" << c << endl << "10 yuan coin number=" << d << endl;
        }
    }
    
    void query(string& s){ //查询函数
        if(s[1] == ' ' && s.length() == 3){ //检查查询命令的合法性
            if(s[2] == 0){ //类别为0
                vector<pair<pair<string, int>, int> > temp;
                for(int i = 0; i < 6; i++) //商品信息入vector方便排序输出
                    temp.push_back(make_pair(make_pair("A" + char(i + 1), price[i]), goods[i]));
                sort(temp.begin(), temp.end(), cmp); //按照重载后的比较排序
                for(int i = 0; i < 6; i++) //输出
                    cout << temp[i].first.first << " " << temp[i].first.second << " " << temp[i].second << endl;
            }
            else if(s[2] == 1){ //类别为1
                cout << "1 yuan coin number=" << coins[0] << endl
                     << "2 yuan coin number=" << coins[1] << endl
                     << "5 yuan coin number=" << coins[2] << endl
                     << "10 yuan coin number=" << coins[3] << endl;
            }
            else
                cout << "E010:Parameter error" << endl;
        }
        else
            cout << "E010:Parameter error" << endl;
    }
};

vector<string> split(string str, const char c){ //通过字符c分割字符串
    vector<string> res;
    istringstream iss(str); // 字符串流输入
    string temp = "";
    while(getline(iss, temp, c)) //根据流输入分割
        res.push_back(temp);
    return res;
}
    
int main(){
    string s;
    while(getline(cin, s)){
        Vending sale; //实例化类
        vector<string> orders = split(s, ';'); //以;分割字符串
        for(auto c: orders){
            switch(c[0]){
                case 'r': //初始化
                    sale.init(c);
                    break;
                case 'p': //投币
                    sale.pay(c);
                    break;
                case 'b': //购买商品
                    sale.buy(c);
                    break;
                case 'c': //退币
                    sale.back();
                    break;
                case 'q': //查询
                    sale.query(c);
                    break;
            }
        }
    }
    return 0;
}

复杂度分析:

  • 时间复杂度:O(n)O(n),其中nn为每次输入的命令的条数,所有操作都是常数时间完成的
  • 空间复杂度:O(1)O(1),常数级空间