牛客华为题库——C++实现【自动售货系统】

牛客网刷题:自动售货系统

本题通过输入相关操作命令实现货物的自动售货找零等。

话不多说,直接开始题目:

描述

1 总体说明

考生需要模拟实现一个简单的自动售货系统,实现投币、购买商品、退币、查询库存商品及存钱盒信息的功能。

系统初始化时自动售货机中商品为6种商品,商品的单价参见1.1规格说明,存钱盒内放置1元、2元、5元、10元钱币,商品数量和钱币张数通过初始化命令设置,参见2.1 系统初始化。

1.1规格说明

1. 商品:每种商品包含商品名称、单价、数量三种属性,其中商品名不重复。考生不能修改商品名称和单价,初始化命令设置商品数量。这些信息在考试框架中进行定义,考生在实现功能代码时可直接使用。

商品 名称

单价

数量

A12X
A23X
A34X
A45X
A58X
A66X

2. 存钱盒信息:钱币面额、张数两种属性。初始化命令设置各种面额钱币张数。这些信息在考试框架中进行定义,考生在实现功能代码时可直接使用。

钱币面额

张数

10元

X

5元

X
2元X
1元X

3. 退币原则 

1) 根据系统存钱盒内钱币的 信息 ,按钱币总张数最少的原则进行退币。

2) 如果因零钱不足导致不能退币,则尽最大可能退币,以减少用户损失。

例如:假设存钱盒内只有4张2元,无其它面额钱币。如果需要退币7元,系统因零钱不足无法退币,则继续尝试退币6元,最终系统成功退币3张2元,用户损失1元钱币。

4. 投币操作说明:每次投币成功,投入的钱币面额累加到投币余额;同时,本次投入的钱币放入存钱盒中,存钱盒相应面额钱币增加。

5. 投币余额:指当前自动售货机中用户剩余的可购买商品的钱币总额;例如:投入2元面额的钱币,投币余额增加2元;购买一件价格2元的商品,投币余额减少2元;

6. 退币操作说明:退币操作需要遵守 退币原则 ;退币成功后,投币余额清零,同时扣除存钱盒相应的金额。

7. 购买商品操作说明:一次仅允许购买一件商品;购买商品成功后,自动售货机中对应商品数量减1,投币余额扣除本次购买商品的价格。

2 操作说明

命令字与第一个参数间使用一个空格分隔,多条命令采用分号隔开。考试系统会对输入命令格式进行处理,考生不需要关注输入命令格式的合法性,只需要实现命令处理函数。

2.1 系统初始化

命令格式

r A1 数量 -A2 数量 -A3 数量 -A4 数量 -A5 数量 -A6 数量 元张数 -2 元张数 -5 元张数 -10 元张数

参数名称

参数说明

类型

取值范围

A1数量

商品A1数量

整数

[0,30]

A2数量

商品A2数量

整数

[0,30]

A3数量

商品A3数量

整数

[0,30]

A4数量

商品A4数量

整数

[0,30]

A5数量

商品A5数量

整数

[0,30]

A6数量

商品A6数量

整数

[0,30]

1元张数

面额1元钱币张数

整数

[0,30]

2元张数

面额2元钱币张数

整数

[0,30]

5元张数

面额5元钱币张数

整数

[0,30]

10元张数

面额10元钱币张数

整数

[0,30]

商品和各种面额钱币取值范围只是作为初始化命令的限制,其它场景下不限制取值范围;考试框架已经实现取值范围的检查,考生不需要关注。

功能说明:设置自动售货机中商品数量和存钱盒各种面额的钱币张数;

约束说明:系统在任意阶段均可执行r初始化系统;考生不需要关注参数的合法性,不需要关注增加或缺少参数的场景;

输出说明:输出操作成功提示(执行完r命令后系统会自动输出操作结果,考生不需要再次调用输出函数),例:

命令输出含义
r 6-5-4-3-2-1 4-3-2-1;S001:Initialization is successful初始化成功

2.2 投币

命令格式钱币面额

功能说明

(1) 如果投入非1元、2元、5元、10元的钱币面额(钱币面额不考虑负数、字符等非正整数的情况),输出“E002:Denomination error”;

(2) 如果存钱盒中1元和2元面额钱币总额小于本次投入的钱币面额,输出“E003:Change is not enough, pay fail”,但投入1元和2元面额钱币不受此限制。

(3) 如果自动售货机中商品全部销售完毕,投币失败。输出“E005:All the goods sold out”;

(4) 如果投币成功,输出“S002:Pay success,balance=X”;

约束说明

(1) 系统在任意阶段都可以投币;

(2) 一次投币只能投一张钱币;

(3) 同等条件下,错误码的优先级:E002 > E003 > E005;

输出说明:如果投币成功,输出“S002:Pay success,balance=X”。

例:

命令

输出

p 10;

S002:Pay success,balance=10

2.3 购买商品

命令格式商品名称

功能说明

(1) 如果购买的商品不在商品列表中,输出“E006:Goods does not exist”;

(2) 如果所购买的商品的数量为0,输出“E007:The goods sold out”;

(3) 如果投币余额小于待购买商品价格,输出“E008:Lack of balance”;

(4) 如果购买成功,输出“S003:Buy success,balance=X”;

约束说明

(1) 一次购买操作仅能购买一件商品,可以多次购买;

(2) 同等条件下,错误码的优先级:E006 > E007 > E008;

输出说明:

如果购买成功,输出“S003:Buy success,balance=X”。

例:

命令

输出

b A1;

S003:Buy success,balance=8

2.4 退币

命令格式c

功能说明

(1) 如果投币余额等于0的情况下,输出“E009:Work failure”;

(2) 如果投币余额大于0的情况下,按照 退币原则 进行“找零”,输出退币信息;

约束说明

(1) 系统在任意阶段都可以退币;

(2) 退币方式必须按照 退币原则 进行退币;

输出说明:如果退币成功,按照 退币原则 输出退币信息。

例,退5元钱币:

命令

输出

c;

1 yuan coin number=0

2 yuan coin number=0

5 yuan coin number=1

10 yuan coin number=0

2.5 查询

命令格式q 查询类别

功能说明

(1) 查询自动售货机中商品信息,包含商品名称、单价、数量。 根据商品数量从大到小进行排序;商品数量相同时,按照商品名称的先后顺序进行排序 

例如:A1的商品名称先于A2的商品名称,A2的商品名称先于A3的商品名称。

(2) 查询存钱盒信息,包含各种面额钱币的张数;

(3) 查询类别如下表所示:

查询类别

查询内容

0

查询商品信息

1查询存钱盒信息

如果“查询类别”参数错误,输出“E010:Parameter error”。“查询类别”参数错误时,不进行下面的处理;

输出说明

“查询类别”为0时,输出自动售货机中所有商品信息(商品名称单价数量)例:

命令

输出

q 0;

A1 2 6

A2 3 5

A3 4 4

A4 5 3

A5 8 2

A6 6 0

“查询类别”为1时,输出存钱盒信息(各种面额钱币的张数),格式固定。例:

命令

输出

q 1;

1 yuan coin number=4

2 yuan coin number=3

5 yuan coin number=2

10 yuan coin number=1

输入描述:

依照说明中的命令码格式输入命令。

输出描述:

输出执行结果

示例1

输入: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;

输出:S001:Initialization is successful

           E009:Work failure

           E010:Parameter error

           S002:Pay success,balance=1

           E008:Lack of balance

           1 yuan coin number=1

           2 yuan coin number=0

           5 yuan coin number=0

           10 yuan coin number=0

           E008:Lack of balance

           E008:Lack of balance

           E009:Work failure

           E010:Parameter error

           S002:Pay success,balance=5

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

class GoodsSaleSystem
{
public:
	GoodsSaleSystem();
	~GoodsSaleSystem();

	void InitSaleSystem();
	void Run(string str);//执行指令

	void Init_r(string cmd);//系统初始化
	void Pay_p(string cmd);//投币
	void Buy_b(string cmd);//购买商品
	void Change_c();//退币
	void Query_q(string cmd);//查询

private:
	//货物单价
	map<string, unsigned int> m_mapGoodsPrice;
	//货物数量
	map<string, unsigned int> m_mapGoodsNum;
	//钱币个数
	map<unsigned int, unsigned int> m_mapMoneyNum;
	//投币余额
	unsigned int m_payMoney;

};

GoodsSaleSystem::GoodsSaleSystem()
{

}

GoodsSaleSystem::~GoodsSaleSystem()
{

}

void GoodsSaleSystem::InitSaleSystem()
{
	m_mapGoodsPrice["A1"] = 2;
	m_mapGoodsPrice["A2"] = 3;
	m_mapGoodsPrice["A3"] = 4;
	m_mapGoodsPrice["A4"] = 5;
	m_mapGoodsPrice["A5"] = 8;
	m_mapGoodsPrice["A6"] = 6;

	m_mapGoodsNum["A1"] = 0;
	m_mapGoodsNum["A2"] = 0;
	m_mapGoodsNum["A3"] = 0;
	m_mapGoodsNum["A4"] = 0;
	m_mapGoodsNum["A5"] = 0;
	m_mapGoodsNum["A6"] = 0;

	m_mapMoneyNum[1] = 0;
	m_mapMoneyNum[2] = 0;
	m_mapMoneyNum[5] = 0;
	m_mapMoneyNum[10] = 0;

	m_payMoney = 0;
}

void GoodsSaleSystem::Run(string str)
{
	vector<string> veccmd;
	string tmp;
	str += ";";//添加一个;便于找到后面一个字段,否则需要判断有;和无;的两种情况处理
	int pos = str.find(";");
	while (pos != string::npos)
	{
		tmp = str.substr(0, pos);

		if (tmp.size() > 0)
			veccmd.push_back(tmp);

		str = str.substr(pos + 1);

		pos = str.find(";");
	}

	for (auto &it : veccmd)
	{
		switch (it[0])
		{
		case 'r':
			Init_r(it);
			break;
		case 'p':
			Pay_p(it);
			break;
		case 'b':
			Buy_b(it);
			break;
		case 'c':
			Change_c();
			break;
		case 'q':
			Query_q(it);
			break;
		}
	}
}

void GoodsSaleSystem::Init_r(string cmd)
{
	if (cmd[0] == 'r' && cmd[1] == ' ')
	{
		cmd = cmd.substr(2);	
		int pos = cmd.find(" ");
		if (pos != string::npos)
		{
			string goodsnumstr;
			string moneynumstr;
			goodsnumstr = cmd.substr(0, pos);
			moneynumstr = cmd.substr(pos + 1);

			string tmp;
			pos = goodsnumstr.find("-");
			for (auto it = m_mapGoodsNum.begin();it != m_mapGoodsNum.end(); it++)
			{
				if (pos == string::npos)
				{
					it->second = stoi(goodsnumstr.c_str());
				}
				else
				{
					tmp = goodsnumstr.substr(0, pos);
					it->second = stoi(tmp.c_str());
					goodsnumstr = goodsnumstr.substr(pos + 1);
					pos = goodsnumstr.find("-");
				}

			}

			pos = moneynumstr.find("-");	
			for (auto it = m_mapMoneyNum.begin(); it != m_mapMoneyNum.end(); it++)
			{
				if (pos == string::npos)
				{
					it->second = stoi(moneynumstr.c_str());
				}
				else
				{
					tmp = moneynumstr.substr(0, pos);
					it->second = stoi(tmp.c_str());
					moneynumstr = moneynumstr.substr(pos + 1);
					pos = moneynumstr.find("-");
				}
			}
			cout <<"S001:Initialization is successful"<<endl;
		}
	}
}

void GoodsSaleSystem::Pay_p(string cmd)
{
	if (cmd[0] == 'p' && cmd[1] == ' ')
	{
		cmd = cmd.substr(2);
		int tmp = stoi(cmd.c_str());
		if (m_mapMoneyNum.find(tmp) != m_mapMoneyNum.end())
		{
			int changetotal = m_mapMoneyNum[1] + m_mapMoneyNum[2] * 2;
			if (tmp != 1 && tmp != 2 && changetotal <= tmp)
			{
				cout << "E003:Change is not enough, pay fail" << endl;
			}
			else
			{
				bool hasleft = false;
				for (auto &it : m_mapGoodsNum)
				{
					if (it.second > 0)
					{
						hasleft = true;
						break;
					}
				}

				if (hasleft)
				{
					m_mapMoneyNum[tmp]++;
					m_payMoney += tmp;
					cout << "S002:Pay success,balance=" << m_payMoney <<endl;	
				}
				else
				{
					cout << "E005:All the goods sold out" << endl;
				}
			}
		}
		else
		{
			cout << "E002:Denomination error" << endl;
		}
	}
}

void GoodsSaleSystem::Buy_b(string cmd)
{
	if (cmd[0] == 'b' && cmd[1] == ' ')
	{
		cmd = cmd.substr(2);

		if (m_mapGoodsNum.find(cmd) != m_mapGoodsNum.end())
		{
			if (m_mapGoodsNum[cmd] == 0)
			{
				cout << "E007:The goods sold out" << endl;
			}
			else
			{
				if (m_payMoney < m_mapGoodsPrice[cmd])
				{
					cout << "E008:Lack of balance" << endl;
				}
				else
				{
					m_payMoney -= m_mapGoodsPrice[cmd];
					cout << "S003:Buy success,balance=" << m_payMoney<<endl;
				}
			}
		}
		else
		{
			cout << "E006:Goods does not exist" << endl;
		}
	}
}

void GoodsSaleSystem::Change_c()
{
	if (m_payMoney == 0)
	{
		cout << "E009:Work failure" << endl;
	}
	else
	{
		stack<string> stkstr;
		string tmp;
		for (auto it = m_mapMoneyNum.rbegin(); it != m_mapMoneyNum.rend(); it++)//从大额开始计算
		{
			unsigned int value = it->first;//面额
			unsigned int num = it->second;//个数
			unsigned int changenum = m_payMoney / value > num ? num : m_payMoney / value;//实际找零个数
			tmp = to_string(value) + " yuan coin number=" + to_string(changenum);
			stkstr.push(tmp);
			m_payMoney -= changenum * value;
		}

		while(stkstr.size())
		{
			string str = stkstr.top();
			cout << str << endl;
			stkstr.pop();
		}	
	}
}

void GoodsSaleSystem::Query_q(string cmd)
{
	if (cmd[0] == 'q' && cmd[1] == ' ')
	{
		cmd = cmd.substr(2);
		if (cmd=="0")
		{
			for (auto it = m_mapGoodsNum.begin(), itor = m_mapGoodsPrice.begin(); it != m_mapGoodsNum.end(), itor != m_mapGoodsPrice.end(); it++, itor++)
			{
				string goodsname = it->first;//货物名 也可使用itor->first
				int price = itor->second;//单价
				int goodsleft = it->second;//个数
				string tmp = goodsname + " "+to_string(price) +" " + to_string(goodsleft);
				cout << tmp << endl;
			}
		}
		else if(cmd == "1")
		{
			for (auto it = m_mapMoneyNum.begin(); it != m_mapMoneyNum.end(); it++)
			{
				int value = it->first;//面额
				int num = it->second;//个数
				string tmp = to_string(value) + " yuan coin number=" + to_string(num);
				cout << tmp << endl;
			}
		}
		else
		{
			cout <<"E010:Parameter error"<< endl;
		}
	}
	else
	{
		cout << "E010:Parameter error" << endl;
	}
}


int main()
{
	string cmdstr;
	GoodsSaleSystem goodssale;
	goodssale.InitSaleSystem();
	while (getline(cin, cmdstr))
	{
		goodssale.Run(cmdstr);
	}

	return 0;
}

首先是在数据结构的选择上,因为投币是1、2、5、10这样的币种进来,很方便转数字,所以m_mapMoneyNum容器的first存的是数字;购买商品的参数传入的是商品名(A1\A2\A3\A4\A5\A6),所以m_mapGoodsNum和m_mapGoodsPrice采用map容器first存的是string类型的商品名字,这样可以减少很多的if/else的逻辑判断,否则需要判断是A1\A2\A3\A4\A5\A6分别做各自逻辑处理。测试中遇到几个案例没有通过,发现是因为这句if (tmp != 1 && tmp != 2 && changetotal < tmp)的原因,题目描述是:“如果存钱盒中1元和2元面额钱币总额小于本次投入的钱币面额,输出“E003:Change is not enough, pay fail”,但投入1元和2元面额钱币不受此限制”。所以我是没有加上等于的,后面修改为if (tmp != 1 && tmp != 2 && changetotal <= tmp)通过了所有测试用例;我觉得这个地方题目描述是不够严谨的,或者是测试用例的通过判断是有误的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值