停车场管理问题
问题描述
设停车场是一个可停放n辆汽车的狭长通道,且只有一个大门可供汽车进出。汽车在停车场内按车辆到达时间的先后顺序,依次由北向南排列(大门在最南端,最先到达的第一辆车停放在车场的最北端)或者由左向右依次排列(大门在右侧,最先到达的第一辆车停放在车场最左侧),若车场内已经停满n辆汽车,则后来的汽车只能在门外的便道上等候,一旦有车开走,则排在便道上的第一辆车即可开入;当停车场内某辆车要离开时,在它之后进入的车辆必须先退出车场为它让路,待该辆车开出大门外,其他车辆再按原次序进入车场,每辆停放在车场的车在它离开停车场时必须按它停留的时间长短交纳费用。请为停车场编制按上述要求进行管理的模拟程序。
基本要求
可使用顺序结构(如结构体数组)模拟停车场,链队(链式存储的队列,考虑倒车退出便道操作方便性,可使用双向链队实现)结构模拟停车场外便道,按照从终端读入的输入数据序列进行模拟管理。
每一组输入数据包括三个数据项:汽车“到达”或“离去”的信息、汽车牌照号码以及到达或离去的时刻。对每一组输入数据进行操作后的输出信息为:若是车辆到达,则输出汽车在停车场内或便道上的停车位置;若是车辆离去,则输出汽车在停车场内停留的时间和应交纳的费用(在便道上停留的时间不收费)。模拟程序可以图形的方式显示,也可以纯文字信息的形式动态显示结果。
实现提示
需要另外设一个栈,临时停放为给要离去的汽车让路而从停车场退出来的汽车,可用顺序或链式存储结构实现。输入数据按到达或离去的时刻有序。无论在停车场内还是在便道上停放的车辆在存储单元中建议使用结点存放该车信息(每个结点存放一辆车的信息,包含两个数据项:汽车的牌照号码和进入停车场的时刻,如需要也可增加数据项存储其他数据)。
测试数据
设n=2,输入数据依次为:(’A’,1,5),(’A’,2,10),(’D’,1,15),(’A’,3,20),(’A’,4,25),(’A’,5,30),(’D’,2,35),(’D’,4,40),(’E’,0,0)。
其中:’A’表示到达,’D’表示离去,’E’表示结束。
选作内容
汽车可以有不同种类,则它们的占地面积不同,收费标准也不同,如1辆客车和1.5辆小汽车的占地面积相同,1辆十轮卡车占地面积相当于3辆小汽车的占地面积。
题解
做法中涵盖了选作内容,因此最终每组输入需要4组数据:车的类型、动作、牌号、时间。在此约定为:
车辆类型:car代表轿车,bus代表客车,truck代表卡车。
收费标准:轿车5元/小时,客车7.5元/小时,卡车15元/小时。
占地面积:轿车1个单位,客车1.5个单位,卡车3个单位。
惯例第一步:先将所需要的类型变量都定义出来。根据题意需要的要有车、停车场、便道。每个车都有不同的几组数据(包括车辆类型、去离情况、牌号、占地面积等),停车场和便道中的每一个元素都可以看作是一辆车,而不同的是停车场需要有容量上限,而便道题目没要求,就假定是可以一直往下排队的。如下:
typedef struct{
string type;//车辆类型
char action;//去离情况
string number;//牌照号码
int time;//去离时间
float area;//占地面积
} Vehicle;//车辆
vector<Vehicle> ParkingLot;//停车场
queue<Vehicle> Sidewalk;//便道
float n;//停车场容量
float num=0;//停车场当前容量
如题,整体流程为:先输入停车场容量,然后再不停地输入停车信息,对每组停车信息进行判断。先输入完信息,要根据车型来确认占地面积,以此在后面来计算收费情况。
Vehicle now;
cout<<"请输入当前车辆信息:(类型 去离情况 牌照号码 时间)";
cin>>now.type>>now.action>>now.number>>now.time;
if(now.type=="car") now.area=1.0;
else if(now.type=="bus") now.area=1.5;
else now.area=3.0;
关键在于判断过程,判断过程要分进来停车还是把车开走这两种情况。
第一种情况还有可能遇到要进来时停车场已经满了,或者要进来时停车场没满。没满就往停车场停,满了就往便道里停。
if(now.action=='A' ){
if(num<n){//停车场未满,进入停车场
ParkingLot.push_back(now);
num+=now.area;
} else {//停车场满,进入便道
Sidewalk.push(now);
}
}
第二种情况把车开走,也要分上述两种可能,如果便道里没有车,说明停车场未满,直接从停车场里开走即可。如果便道里有车,说明停车场满了,这时候停车场里开走一辆,便道里的第一辆车还要开进停车场。
else if(now.action=='D'){
leave(now);
if(!Sidewalk.empty()){//便道里有车,还要再进来一个
Vehicle t = Sidewalk.front();
Sidewalk.pop();
ParkingLot.push_back(t);
}
}
根据每次进出情况进行操作以后,停车情况了,这里使用一个函数output()
来输出整体情况。
在上述分析中,离开停车场时使用的leave()
函数中,每次离开都需要输出收费情况。在停车场中查找时用的遍历查询,查到牌号以后根据进出的时间差以及车辆占地面积来计算收费。计算公式为:收费=(离开时间-进入时间)×占地面积×5元/占地面积。由于使用到遍历了,顺带我们还要考虑一下这种情况,当用户输入想要离开停车场时,如果这辆车在这之前并未进入停车,那显然是输入错误,还需要应对一下这种情况。
void leave(Vehicle now){//离开停车场
int t; //停车时间
for(vector<Vehicle>::iterator it=ParkingLot.begin();it!=ParkingLot.end();it++){
if(it->number==now.number){
t = now.time - it->time;
it=ParkingLot.erase(it);
cout<<"车牌号:"<<now.number<<"----收费:"<<t*now.area*5<<"元"<<endl;
return;
}
}
cout<<"输入不合法:该车辆不在停车场内。"<<endl;
}
在最终的输出函数中,只需要分别遍历停车场和便道,即可得到每一辆车的数据。
void output(){//停车情况
cout<<setiosflags(ios::left);
cout<<"当前停车场内的车辆:"<<endl;
cout<<"|类型: |"<<"牌号: |"<<endl;
for(vector<Vehicle>::iterator it=ParkingLot.begin();it!=ParkingLot.end();it++){
cout<<"|"<<setw(11)<<it->type<<"|"<<setw(13)<<it->number<<"|"<<endl;
}
cout<<"当前便道内的车辆:"<<endl;
cout<<"|类型: |"<<"牌号: |"<<endl;
for(int i=0;i<Sidewalk.size();i++){
Vehicle t = Sidewalk.front();
Sidewalk.pop();
cout<<"|"<<setw(11)<<t.type<<"|"<<setw(13)<<t.number<<"|"<<endl;
Sidewalk.push(t);
}
cout<<endl;
}
完成了以上内容,实际工作已经能够实现。但是这里还考虑到一点异常处理:就是当用户输入停一辆车时,如果这辆车已经位于停车场内或者便道内,那么说明用户的输入有问题,这时候需要有个异常处理才行。所以每次输入进停车场时都要加上这么一个判断。这个判断过程实际上也就是一个遍历过程。但是有一点是,停车场我们使用是一个容器来存,可以定义一个迭代器用来遍历,但是便道使用的是一个队列来存,队列是无法直接遍历的,因为它没有方法能返回队首指针或者队尾指针,所以采取的方式是每次把读取队首元素,并把队首元素出队又继续入队。
bool judge(Vehicle now){//判断车辆是否已经进入
int flag=1;
for(vector<Vehicle>::iterator it=ParkingLot.begin();it!=ParkingLot.end();it++){
if(it->number==now.number){
cout<<"输入不合法:该车辆已经位于停车场内。"<<endl;
return false;
}
}
for(int i=0;i<Sidewalk.size();i++){
Vehicle t = Sidewalk.front();
Sidewalk.pop();
Sidewalk.push(t);
if(t.number==now.number){
flag=0;
cout<<"输入不合法:该车辆已经位于便道内。"<<endl;
}
}
if(flag) return true;
else return false;
}
想到了上述这么一个异常输入情况,立马容易想到,其实还要很多异常情况,例如:
一、用户输入一辆车离开,但是离开时间在进入时间之前。
二、输入的车型既不是car,也不是bus,也不是trunk。
三、没有按照约定顺序输入。
……
想到以上问题,我就不再往下想象了,想要应对所有异常情况工作量还是比较大,所以用户输入的时候还是好好按规矩输入吧。反正核心思想已经有了,有兴趣的朋友再自行补充吧。
最后附上全部代码以及运行示例:
#include<iostream>
#include<queue>
#include<vector>
#include<iomanip>
using namespace std;
/**
车辆类型:car代表轿车,bus代表客车,truck代表卡车。
收费标准:轿车5元/小时,客车7.5元/小时,卡车15元/小时。
占地面积:轿车1个单位,客车1.5个单位,卡车3个单位。
*/
typedef struct{
string type;//车辆类型
char action;//去离情况
string number;//牌照号码
int time;//去离时间
float area;//占地面积
} Vehicle;//车辆
vector<Vehicle> ParkingLot;//停车场
queue<Vehicle> Sidewalk;//便道
float n;//停车场容量
float num=0;//停车场当前容量
bool judge(Vehicle now){//判断车辆是否已经进入
int flag=1;
for(vector<Vehicle>::iterator it=ParkingLot.begin();it!=ParkingLot.end();it++){
if(it->number==now.number){
cout<<"输入不合法:该车辆已经位于停车场内。"<<endl;
return false;
}
}
for(int i=0;i<Sidewalk.size();i++){
Vehicle t = Sidewalk.front();
Sidewalk.pop();
Sidewalk.push(t);
if(t.number==now.number){
flag=0;
cout<<"输入不合法:该车辆已经位于便道内。"<<endl;
}
}
if(flag) return true;
else return false;
}
void leave(Vehicle now){//离开停车场
int t; //停车时间
for(vector<Vehicle>::iterator it=ParkingLot.begin();it!=ParkingLot.end();it++){
if(it->number==now.number){
t = now.time - it->time;
it=ParkingLot.erase(it);
cout<<"车牌号:"<<now.number<<"----收费:"<<t*now.area*5<<"元"<<endl;
return;
}
}
cout<<"输入不合法:该车辆不在停车场内。"<<endl;
}
void output(){//停车情况
cout<<setiosflags(ios::left);
cout<<"当前停车场内的车辆:"<<endl;
cout<<"|类型: |"<<"牌号: |"<<endl;
for(vector<Vehicle>::iterator it=ParkingLot.begin();it!=ParkingLot.end();it++){
cout<<"|"<<setw(11)<<it->type<<"|"<<setw(13)<<it->number<<"|"<<endl;
}
cout<<"当前便道内的车辆:"<<endl;
cout<<"|类型: |"<<"牌号: |"<<endl;
for(int i=0;i<Sidewalk.size();i++){
Vehicle t = Sidewalk.front();
Sidewalk.pop();
cout<<"|"<<setw(11)<<t.type<<"|"<<setw(13)<<t.number<<"|"<<endl;
Sidewalk.push(t);
}
cout<<endl;
}
int main(){
cout<<"请输入停车场的容量n(以小轿车为单位):";
cin>>n;
while(1){
Vehicle now;
cout<<"请输入当前车辆信息:(类型 去离情况 牌照号码 时间)";
cin>>now.type>>now.action>>now.number>>now.time;
if(now.type=="car") now.area=1.0;
else if(now.type=="bus") now.area=1.5;
else now.area=3.0;
if(now.action=='A' && judge(now)){
if(num<n){//停车场未满,进入停车场
ParkingLot.push_back(now);
num+=now.area;
} else {//停车场满,进入便道
Sidewalk.push(now);
}
}
else if(now.action=='D'){
leave(now);
if(!Sidewalk.empty()){//便道里有车,还要再进来一个
Vehicle t = Sidewalk.front();
Sidewalk.pop();
ParkingLot.push_back(t);
}
}
output();
}
return 0;
}