题目
实验背景
你是一家药店的老板,这个月你从供货商手里收到了一批共50个药品, 其中每个药品有独立的进价和保质期,其中进价的区间为[20,30]元,保质期的剩余天数为[1,15]天,你每天可以陈列出10个药品在商店中售卖,每天会有三个顾客各过来购买一个药品。 药品的定价只能为商品进价加上{-1.5,-1, -0.5, 0, 2 ,4 ,6}元,不得随意定价。 每位顾客购买的逻辑是,买其中最便宜的药品,如果说最便宜的药品价格一致则购
买保质期⻓的药品。 三位顾客会依次购买药品。 药品如果没有陈列在商店中,而是存放在仓库时,会收取管理费,其中保质期低于5天的每天收取1元管理费,其余的每天收取0.5元。
药品过期当天丢弃
每天的陈列药品可以少于10个
你的目标是,10天之后,你的利润(售出商品售价总和-售出商品进价总和-支付仓库的管理费用-10天内过期/丢弃商品的进价)最大。
实验要求
能够完整的模拟整个流程,给定药品的进价以及保质期,给定每天陈列的药品,可以直接得到商家的利润;
能够自己制定每天展示的药品策略,给定一定的进价和保质期的药品,能够自己指定策略,得到利润;
代码逻辑清晰,条理清楚;
一、问题描述
- 药品具有独立的进价和保质期
进价的区间为[20,30]元,保质期的剩余天数为[1,15]天 - 每天可以陈列出10个药品在商店中售卖
每天会有三个顾客各过来购买⼀个药品 - 定价只能为商品进价加上{-1.5,-1,-0.5,0, 2,4,6}元
- 每位顾客购买的逻辑是,买其中最便宜的药品
最便宜的药品价格⼀致则购买保质期⻓的药品 - 药品存放在仓库时,会收取管理费
保质期低于5天的每天收取1元管理费,其余的每天收取0.5元 - 药品过期当天要丢掉
每天陈列的样品可以少于10个 - 利润=售价总和-进价总和-管理费用-10天内过期/丢弃商品的进价
目标是十天后利润最大
二、实现策略
- 模拟方法:
包含三个类:药品类、药品列表、模拟药店
药品类中包含药品的ID号、保质期、成本
药品列表包含一个药品型的数组、药品总数
函数包含插入药品、删除药品、调整药品状态(上架或存放在仓库)、按价格或保质期排序、药品下架入库等功能
模拟药店类包含天数、一个药品列表、总利润
函数有读取文件medicine.txt信息的构造函数、删除过期药品、模拟教辅数据、模拟自己的最有策略等功能 - 将药品按保质期排序,保质期小的放在数组前面
保质期相同的,比较价格,价格高的放在数组前面
出售时,按排序后的顺序出售,每次售卖三个药品,利润定为6 - 将价格高于出售药品的药品摆上货架
- 对药品实行预处理,即对于必然会丢弃的药品,在第一天就丢弃,则不用交付管理费
实现方法:丢弃药品时,加回该药品这几天交的管理费
三、代码实现
(一) 药品类medicine.h的编写
私有成员包含药品ID号、生产日期、成本
private:
int ID;
int data; //保质期
double cost; //成本
共有函数:初始化、为私有成员提供接口
medicine::medicine(int id=-1, int d=0, double c=0):
ID(id), data(d), cost(c), state(0)
{}
int medicine::getID(void)
{
return ID;
}
int medicine::getData(void)
{
return data;
}
double medicine::getCost(void)
{
return cost;
}
//删除药品只需把ID改为-1
void medicine::delete_medicine(void)
{
ID = -1;
}
(二) 药品队列类med_list.h的编写
私有成员包括药品总数和药品数组,最大药品数设为50
#define MaxMedSize 50
定义药品类这个数据结构
typedef medicine DataType;
私有成员:药品总数、药品数组
private:
int amount;
DataType MedList[MaxMedSize];
公共函数:
public:
med_list(void); //初始化
void MedInsert(int id, int d, double c); //药品进货
DataType findMed(int id); //查看药品
void changeState(int id, int st); //调整药品状态
void deleteMed(int id); //卖出、丢弃药品
void sort_MedList_data_cost(void); //优先按保质期排序,相等时再按价格排序
void removeMed(void); //药品下架入库
int getAmount(void);
int getNotSell(void);
构造函数,将药品数量置为0,不卖药品数置为0
med_list::med_list(void) : amount(0), notSell(0)
{}
插入药品函数
当药品数达到50个时,输出已满信息
void med_list::MedInsert(int id, int d, double c)
{
if(amount == MaxMedSize)
{
cout << "药品已满" << endl;
exit(1);
}
medicine tmp(id, d, c);
MedList[id] = tmp;
amount++;
}
返回药品,用于下一个文件提取药品
DataType med_list::findMed(int id)
{
return MedList[id];
}
改变药品状态,上架时置为1,收回仓库置为0
void med_list::changeState(int id, int st)
{
MedList[id].state = st;
}
删除药品
当药品丢弃或卖出时执行该操作
将该药品id置为-1,药品总数减1
void med_list::deleteMed(int pos)
{
MedList[pos].delete_medicine();
amount--;
}
将药品从架子上取回,放回仓库
遍历药品数组,将所有药品的状态置为1
void med_list::removeMed(void)
{
for(int i=0; i<MaxMedSize; i++)
{
if(MedList[i].state == 1)
MedList[i].state = 0;
}
}
排序,优先按保质期排序,保质期相等的情况下按价格排序
保质期短、价格昂贵的排在前面
//时间紧的在前面
void med_list::sort_MedList_data_cost(void)
{
for(int i=0; i<MaxMedSize; i++)
{
for(int j=i+1; j<MaxMedSize; j++)
{
if(MedList[i].getData() > MedList[j].getData())
{
medicine tmp = MedList[i];
MedList[i] = MedList[j];
MedList[j] = tmp;
}
else if(MedList[i].getData() == MedList[j].getData() && MedList[i].getCost() < MedList[j].getCost())
{
medicine tmp = MedList[i];
MedList[i] = MedList[j];
MedList[j] = tmp;
}
}
}
}
(三) 实现simulation,模拟给定数据
(med_store.h模拟部分、runsimulation.cpp)
1.
私有成员:天数、总利润、药品列表
private:
int day;
double tProfit;
med_list ml;
共有函数:构造函数、管理费用、删除过期药品、模拟
med_store(char *filename);
void GetManagePrice(void);
void delete_overdue_decision(char *filename);
void decision(char *filename, char *delname);
构造函数中,将medicine.txt当作参数输入
读取药品参数,生产药品列表
med_store::med_store(char *filename)
{
day = 0;
tProfit = 0;
FILE *fp = fopen(filename, "r");
for(int i=0; i<MaxMedSize; i++)
{
int d;
double c;
fscanf(fp, "%lf\t%d\n", &c, &d);
ml.MedInsert(i, d, c);
}
fclose(fp);
}
收取管理费,遍历药品列表,对未删除、状态为在库内的药品收取费用
保质期5天一下利润减1元,5天以上减0.5元
void med_store::GetManagePrice(void)
{
for(int i=0; i<50; i++)
{
if(ml.findMed(i).getData()-day <= 5 && ml.findMed(i).getID() != -1 && ml.findMed(i).state == 0)
tProfit -= 1;
else if(ml.findMed(i).getID() != -1 && ml.findMed(i).state == 0)
tProfit -= 0.5;
}
}
删除过期药品,读取delete.txt文件
遍历文件中所有要删除的药品,将保质期与天数进行对比
若相等,则删去该药品,并从利润中扣去该药品的进价
void med_store::delete_overdue_decision(char *filename)
{
FILE *fp = NULL;
fp = fopen(filename, "r");
int d;
int id;
while(fscanf(fp, "%d\t%d\n", &d, &id)!=EOF)
{
if(day == d)
{
ml.deleteMed(id);
tProfit -= ml.findMed(id).getCost();
}
}
fprintf(fp, "\n");
fclose(fp);
}
模拟数据,读取strategy.txt文件
将strategy.txt和delete.txt作为参数输入
void med_store::decision(char *filename, char *delname)
生产利润索引
double profit_list[7] = {-1.5, -1, -0.5, 0, 2 ,4 ,6};
遍历10天(即10行)
for(int i=0; i<10; i++)
{
day = i;
double price[10];
int id_list[10], num = 0;
for(int j=0; j<10; j++)
price[j] = 10000;
遍历这一天的10件商品
将每天的药品卖价(=进价+利润)存入price数组
将id号存入id_list数组
将药品状态置为“上架”
for(int j=0; j<10; j++)
{
int id;
int suoyin;
fscanf(fp, "%d,%d\t", &id, &suoyin);
double c = profit_list[suoyin];
if(id != -1)
{
ml.changeState(id, 1);
price[num] = ml.findMed(id).getCost() + c;
id_list[num] = id;
num++;
}
fscanf(fp, "\n");
}
/*
对这一天的药品卖价进行排序
价格低的放在前面
价格相等时,保质期长的放在前面
price和id_list要同时进行移动操作
*/
for(int j=0; j<num; j++)
{
for(int k=j+1; k<num; k++)
{
if(price[j] > price[k])
{
double tmp0 = price[j];
price[j] = price[k];
price[k] = tmp0;
int tmp1 = id_list[j];
id_list[j] = id_list[k];
id_list[k] = tmp1;
}
else if(price[j] == price[k] && ml.findMed(j).getData() > ml.findMed(k).getData())
{
double tmp0 = price[j];
price[j] = price[k];
price[k] = tmp0;
int tmp1 = id_list[j];
id_list[j] = id_list[k];
id_list[k] = tmp1;
}
}
}
/*
筛选出当天价格最低的三个药品,最先卖出
删除药品,从总利润中减去药品进价
*/
for(int j=0; j<3; j++)
{
ml.changeState(id_list[j], 1);
tProfit += price[j] - ml.findMed(id_list[j]).getCost();
ml.deleteMed(id_list[j]);
}
//收取管理费、药品下架、清除过期药品
this->GetManagePrice();
ml.removeMed();
this->delete_overdue_decision(delname);
编写runsimulation.cpp文件
传入头地址和三个文件的命名
char top[] = "D:\\data\\simulation\\data";
char readfiletail[] = "\\medicine.txt";
char strategytail[] = "\\strategy.txt";
char deletetail[] = "\\delete.txt";
循环10次,运行10个data文件
for (int i = 1; i < 11; i++)
//将文件路径拼接在一起
char *MedFilename = (char *)malloc(strlen(top) + strlen(number) + strlen(readfiletail));
char *StrFilename = (char *)malloc(strlen(top) + strlen(number) + strlen(strategytail));
char *DelFilename = (char *)malloc(strlen(top) + strlen(number) + strlen(deletetail));
//将字符串格式化
sprintf(MedFilename, "%s%s%s", top, number, readfiletail);
sprintf(StrFilename, "%s%s%s", top, number, strategytail);
sprintf(DelFilename, "%s%s%s", top, number, deletetail);
//运行
med_store ms(MedFilename);
ms.decision(StrFilename, DelFilename);
(四) 实现自己的策略
(med_store最优策略部分、BestBenefit.cpp)
1.
公有函数:新增策略函数、修改删除药品函数
med_store(char *filename);
void GetManagePrice(void);
void delete_overdue(char *filename);
void strategy(char *filename);
int get_day(void);
double get_tProfit(void);
double get_tCost(void);
void simulation(char *StrFilename, char *DelFilename);
删除药品函数
如果是第一次打开delete.txt文件,则覆盖原文件内容
从第二次开始,在文件后面更新输入内容
在原删除函数的基础上添加了预处理功能
即将要丢弃的药品在第一天就丢弃,减少管理费用
方法:丢弃时,将收取的管理费加回来
保质期大于5天的加0.5元,小于5天加1元
void med_store::delete_overdue(char *filename)
{
FILE *fp = NULL;
if(day == 0)
fp = fopen(filename, "w");
else
fp = fopen(filename, "a+");
fprintf(fp, "第%d天:", day);
for(int i=0; i<MaxMedSize; i++)
{
if(ml.findMed(i).getData() == day && ml.findMed(i).getID() != -1)
{
fprintf(fp, "%d,%lf\t", ml.findMed(i).getID(), ml.findMed(i).getCost());
ml.deleteMed(i);
tProfit -= ml.findMed(i).getCost();
if(day >= 5)
tProfit += (day-5) * 0.5 + 5 * 1;
else
tProfit += day * 1;
}
}
fprintf(fp, "\n");
fclose(fp);
}
策略函数:将策略写入strategy.txt文件中
void med_store::strategy(char *filename)
先将药品列表按保质期为最高优先级排序
ml.sort_MedList_data_cost();
选择卖出药品
卖出药品列表中的排序前3的药品,利润全部设为6
int sellNum = 0, i = 0, maxPrice = 0;
while(sellNum != 3 && i < MaxMedSize)
{
if(ml.findMed(i).getID() != -1){
ml.changeState(ml.findMed(i).getID(), 1);
if(maxPrice < ml.findMed(i).getCost())
maxPrice = ml.findMed(i).getCost();
tProfit += 6;
fprintf(fp, "卖出:%d,%.4lf\t", ml.findMed(i).getID(), ml.findMed(i).getCost() + 6);
ml.deleteMed(i);
sellNum++;
}
i++;
}
选择摆上架子但不出售的药品
在列表中选出价格高于出售药品的药品
最多可上架7个
上架的药品状态置为1
int shangjiaNum = 0, j = 0;
while(shangjiaNum != 7 && j < MaxMedSize)
{
if(ml.findMed(j).getID() != -1 && ml.findMed(j).state != 1 && ml.findMed(j).getCost() > maxPrice)
{
ml.changeState(ml.findMed(j).getID(), 1);
shangjiaNum++;
fprintf(fp, "上架:%d,%.4lf\t", ml.findMed(j).getID(), ml.findMed(j).getCost() + 6);
}
j++;
}
simulation函数模拟整个策略
天数由0增至9
每天执行卖药上架策略、删除过期药品、收取管理费、药品下架入库、天数自增
循环结束后,输出总利润
while(day < 10)
{
this->strategy(StrFilename);
this->delete_overdue(DelFilename);
this->GetManagePrice();
ml.removeMed();
day++;
}
cout << tProfit << endl;