题目要求
1 总体说明
考生需要模拟实现一个简单的购物结算系统,实现挑选和删除商品、按照最佳优惠方案进行结算、查询购物车订单信息及购物卡余额和积分的功能。
系统初始化时购物卡中有3000元余额和150积分,可以输入命令来初始化系统。
1.1 购物活动细则
只要购物卡余额足够,可以进行多次购买,每次购买活动可以包含如下活动:
1、多次挑选商品,每次挑选形成购物车中的一条商品订单;
2、多次删除商品订单,每次只能删除一条订单;
结算的是当前购物车中所有订单,结算完成即本次购买活动结束,同时清空购物车并更新购物卡余额和积分;
1.2 商品优惠细则
购买商品时优惠方案分为单项优惠方案和总价优惠方案,在享受单项优惠的同时如满足一定条件可以再享受总价优惠。
各种商品的单项优惠方案列表:
单项优惠方案序号:
1、在一次购买活动中,同种商品只能有一种单项优惠方案;总价优惠方案:在一次购买活动结算时,所有商品单项优惠后总消费金额大于等于500时,可以再使用“积分抵现”或“折上折”优惠:
(1) 积分抵现:1个积分抵1元现金,购物卡积分大于等于120只能使用120个积分,不足120,全部使用;
(2) 折上折:在单项商品优惠后总金额基础上,再打8折;
1.3 约束
* 商品价格最小单位到元,所有涉及价格计算中不足1元,向下取整,舍掉余数部分。例如:计算出的实际价格为563.9,则取整为563;
* 本次购买活动新增的积分不能在当次购买中使用;
* 购物卡余额和积分不能透支;
2 操作说明
命令字与第一个参数间使用一个空格分隔,多个参数间使用半角“-”分隔,参数间没有空格。考试系统会对输入命令格式进行处理,考生不需要关注输入命令格式的合法性,只需要实现命令处理函数。对于涉及多个参数的命令,多个参数同时出错的情况不作为考察点。
2.1 系统初始化
命令格式:r
功能说明:将购物卡金额和积分分别初始化为3000、150;
约束说明:系统在任意阶段均可执行r初始化系统;
输出说明:输出操作成功提示(执行完r命令后系统会自动输出操作结果,考生不需要再次调用输出函数),例:
2.2 挑选商品
命令格式:o 商品序号-商品数量
功能说明:
(1) 每次挑选只能指定一种商品,且商品数量不超过100(0<每次挑选商品数量<=100),同一种商品可以多次挑选;
(2) 挑选成功则生成购物车中的一条商品订单,输出:“S002”;
(3) 如果输入的“商品序号”或“商品数量”参数不合法,输出“E002”。参数错误直接返回不再进行其他处理;
(4) 购物车中最多容纳5条商品订单,挑选时如果购物车已满,则挑选失败,输出“E003”;
(5) 在挑选商品阶段不校验购物卡余额是否足够;
约束说明:
(1) 系统在任意阶段都可以挑选商品;
(2) 购物车中的同一种商品的订单记录不合并;
输出说明:如果挑选成功,输出操作提示。例,挑选6本书籍:
2.3 删除商品订单记录
命令格式:c 商品序号-商品数量
功能说明:
(1) 在结账前可以删除购物车中的订单以取消挑选,商品数量不超过100(0<每次删除商品数量<=100),每次只能删除一条,可以执行多次删除操作;
(2) 只能删除购物车中与删除命令输入的“商品序号”、“商品数量”完全匹配的订单记录;
(3) 如果输入的“商品序号”或“商品数量”参数不在系统允许的范围内,输出“E002”。参数错误直接返回不再进行其他处理;
(4) 如果购物车为空,输出“E005”;
(5) 如果购物车中不存在待删除订单,输出“E004”;
(6) 如果购物车中存在多条相同(“商品序号”和“商品数量”都相同)的订单记录,则只删除购物车中的一条记录;
输出说明:如果删除成功,输出操作提示。例,从购物车中删除6本书籍的订单记录:
2.4 结算
命令格式:b
功能说明:
(1) 系统根据“商品优惠细则”自动调整商品的单项和总价优惠方案,使得用户消费金额最少。当两种总价优惠方案花费金额相同时,优选“折上折”。
(2) 如果购物车为空,输出“E005”;
(3) 如果购物卡余额或积分不足以购买购物车商品时,输出“E006”;
输出说明:如果结算成功,输出结果中包含本次购买所需的消费金额和消费积分以及新增的积分。例:
2.5 查询
命令格式:l 查询类别
功能说明:
(1) 查询购物卡信息(余额、积分)和购物车中的订单信息;
(2) 查询类别:0表示购物卡信息查询,1表示购物车订单查询;如果“查询类别参数错误,输出“E002”。“查询类别”参数错误时,不进行下面的处理。
输出说明:
(1) “查询类别”为0时,输出购物卡余额和积分,例:
(2) “查询类别”为1时,输出购物车中的订单数以及每种商品的总数,例:
2.6结束
命令格式:e 系统结束 功能说明:一次购物完成,系统结束。
输入:
依照说明中的命令码格式输入命令
输出:
输出执行结果
样例输入:
r
o 1-100
e
样例输出:
S001
S002
3 附录:
3.1 命令汇总
3.2 返回码汇总
3.3 基本用例
解题思路
1、初始化与退出操作位于测试用例的开头和结尾。这个结算系统只针对一个消费者的一次活跃的的购物过程,当该消费者选择退出时,结算系统也退出,即程序退出。
2、使用数组来记录购物单。系统规定购物车最多可以存储5个购物单,因此使用数组来记录,没有选择插入删除操作比较方便的链表。购物车数组初始化时被清零,如果有购物单加入购物车,则直接选择数组中为0的单元记录新的购物单信息。删除购物单时,则找到目标单元清零即可。
3、结算的时候计算各商品的单价优惠方案总和最多有12种结果,在这12中结果中筛选出小于500元的范围内的最小花费和大于等于500的范围内的最小花费。然后在进行总价优惠方案的判断。
代码实现
#include <iostream>
#include <string>
using namespace std;
#define SIZE 5 //购物车数组长度
typedef struct {
int seq;//商品分类号
int number;//商品数目
}GOODS;
typedef struct {
int money;//余额
int points;//积分
int numOfGoods;//购物车内清单数目
GOODS shoppingCart[SIZE];//购物车数组
}CUSTOMER;
//初始化购物结算系统
void initShoppingSystem(CUSTOMER &customer) {
customer.money = 3000;
customer.points = 150;
customer.numOfGoods = 0;
memset(customer.shoppingCart, 0, sizeof(GOODS) * SIZE);
cout << "S001" << endl;
return;
}
//提取指令参数(只针对格式正确的指令)
void getGoodsRequirement(string &cmd, GOODS &goods) {
int i = 1, num = 0, len = cmd.size();
while (cmd[i] == ‘ ‘) {
i++;
}
goods.seq = (cmd[i] - ‘0‘);
for (i += 2; i < len; i++) {
num = num * 10 + (cmd[i] - ‘0‘);
}
goods.number = num;
return;
}
//挑选商品
void selectGoods(CUSTOMER &customer, string &cmd) {
GOODS goods;
int i;
getGoodsRequirement(cmd, goods);
if (goods.number > 100 || goods.number < 1 || goods.seq < 0 || goods.seq > 2) {
cout << "E002" << endl;
return;
}
if (customer.numOfGoods == 5) {
cout << "E003" << endl;
return;
}
for (i = 0; i < SIZE; i++) {
if (customer.shoppingCart[i].number == 0 &&
customer.shoppingCart[i].seq == 0) {
memcpy(&(customer.shoppingCart[i]), &goods, sizeof(GOODS));
customer.numOfGoods++;
break;
}
}
cout << "S002" << endl;
return;
}
//删除商品
void deleteGoods(CUSTOMER &customer, string &cmd) {
GOODS goods;
int i;
getGoodsRequirement(cmd, goods);
if (goods.number > 100 || goods.number < 1 || goods.seq < 0 || goods.seq > 2) {
cout << "E002" << endl;
return;
}
if (customer.numOfGoods == 0) {
cout << "E005" << endl;
return;
}
for (i = 0; i < SIZE; i++) {
if (customer.shoppingCart[i].number == goods.number &&
customer.shoppingCart[i].seq == goods.seq) {
memset(&(customer.shoppingCart[i]), 0, sizeof(GOODS));
customer.numOfGoods--;
break;
}
}
if (i == SIZE) {
cout << "E004" << endl;
}
else {
cout << "S003" << endl;
}
return;
}
//结算
void buyGoods(CUSTOMER &customer) {
int food = 0, clothes = 0, book = 0, price1, price2, custom = 0, p = 0;
int sum[2] = { 0 }, foodSum[3] = { 0 }, clothesSum[2] = { 0 }, bookSum[2] = { 0 };
int i, j, k, l = 0, tmp;
if (customer.numOfGoods == 0) {
cout << "E005" << endl;
return;
}
/*
统计各类商品所需的总金钱数目
*/
for (i = 0; i < SIZE; i++) {
if (customer.shoppingCart[i].number == 0) {
continue;
}
switch (customer.shoppingCart[i].seq)
{
case 0:
food += 10 * customer.shoppingCart[i].number;
break;
case 1:
clothes += 120 * customer.shoppingCart[i].number;
break;
case 2:
book += 30 * customer.shoppingCart[i].number;
break;
default:
break;
}
}
/*
食品应用单价优惠方案后的所需金钱数目
*/
if (food > 0) {
foodSum[0] = food;
foodSum[1] = (food / 10) * 9;
foodSum[2] = food - (food / 100) * 18;
}
/*
衣服应用单价优惠方案后的所需金钱数目
*/
if (clothes > 0) {
clothesSum[0] = clothes;
clothesSum[1] = clothes - (clothes / 200) * 40;
}
/*
书籍应用单价优惠方案后的所需金钱数目
*/
if (book > 0) {
bookSum[0] = book;
bookSum[1] = book / 2;
}
for (i = 0; i < 3; i++) {
for (j = 0; j < 2; j++) {
for (k = 0; k < 2; k++) {
tmp = foodSum[i] + clothesSum[j] + bookSum[k];
if (tmp > 0) {
/*
筛选出位于大于等于500元范围内的最小金钱数目
*/
if (tmp >= 500) {
if (sum[1] == 0) {
sum[1] = tmp;
}
else {
sum[1] = sum[1] > tmp ? tmp : sum[1];
}
}
/*
筛选出位于小于500元范围内的最小金钱数目
*/
else {
if (sum[0] == 0) {
sum[0] = tmp;
}
else {
sum[0] = sum[0] > tmp ? tmp : sum[0];
}
}
}
}
}
}
/*
适用于总价优惠方案的金钱数目处理
*/
if (sum[1] > 0) {
price1 = (int)((double)sum[1] * 0.8);
p = customer.points >= 120 ? 120 : customer.points;
price2 = sum[1] - p;
if (price1 <= price2) {
sum[1] = price1;
p = 0;
}
else {
sum[1] = price2;
}
}
/*
两个范围内的金钱数目均存在
*/
if (sum[0] > 0 && sum[1] > 0) {
if (sum[0] < sum[1]) {
custom = sum[0];
p = 0;
}
else {
custom = sum[1];
if (p != 0) {
customer.points -= p;
}
}
}
/*
只存在大于等于500元的金钱数目,考虑是否使用积分
*/
else if (sum[0] == 0 && sum[1] > 0) {
custom = sum[1];
if (p != 0) {
customer.points -= p;
}
}
/*
只存在小于500元的金钱数目
*/
else if (sum[0] > 0 && sum[1] == 0) {
custom = sum[0];
p = 0;
}
if(custom > customer.money) {
cout << "E006" << endl;
return;
}
customer.money -= custom;
customer.points += (custom / 10);
memset(customer.shoppingCart, 0, sizeof(GOODS)*SIZE);
customer.numOfGoods = 0;
cout << custom << endl;
cout << p << endl;
cout << custom / 10 << endl;
return;
}
//查询操作
void lookup(CUSTOMER &customer, string &cmd) {
int i = 1, sum = 0, food = 0, clothes = 0, book = 0;
int len = cmd.size();
while (cmd[i] == ‘ ‘) {
i++;
}
for (; i < len; i++) {
sum = sum * 10 + (cmd[i] - ‘0‘);
}
if (sum != 0 && sum != 1) {
cout << "E002" << endl;
return;
}
//查询余额与积分
if (sum == 0) {
cout << customer.money << endl;
cout << customer.points << endl;
}
//查询购物车信息
else if (sum == 1)
{
for (i = 0; i < SIZE; i++) {
if (customer.shoppingCart[i].number == 0) {
continue;
}
switch (customer.shoppingCart[i].seq)
{
case 0:
food += customer.shoppingCart[i].number;
break;
case 1:
clothes += customer.shoppingCart[i].number;
break;
case 2:
book += customer.shoppingCart[i].number;
break;
default:
break;
}
}
cout << customer.numOfGoods << endl;
cout << food << endl;
cout << clothes << endl;
cout << book << endl;
}
return;
}
int main() {
string cmd;
CUSTOMER customer;
int exitFlag = 0;
while (exitFlag == 0) {
getline(cin, cmd);
switch (cmd[0])
{
case ‘r‘:
initShoppingSystem(customer);
break;
case ‘o‘:
selectGoods(customer, cmd);
break;
case ‘c‘:
deleteGoods(customer, cmd);
break;
case ‘b‘:
buyGoods(customer);
break;
case ‘l‘:
lookup(customer, cmd);
break;
case ‘e‘:
exitFlag = 1;
break;
default:
break;
}
}
return 0;
}
加油!!!!