每周一题(9)

停车场管理问题

问题描述

      设停车场是一个可停放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;
} 

在这里插入图片描述
在这里插入图片描述

设有一个可以停放n辆汽车的狭长停车场,它只有一个大门可以供车辆进出。车辆按到达停车场时间的早晚依次从停车场最里向大门口处停放(最先到达的第一辆车放在停车场的最里面)。如果停车场已放满n辆车,则后来的车只能在停车场大门外的便道上等待,一旦停车场内有车开走,则排在便道上的第一辆车就进入停车场。停车场内如有某辆车要开走,在它之后进入停车场的车都必须先退出停车场为它让路,待其开出停车场后,这些车辆再依原来的次序进场。每辆车在离开停车场时,都应根据它在停车场内停留的时间长短交费。如果停留在便道上的车未进停车场就要离去,允许其离去,不收停车费,并且仍然保持在便道上等待的车辆次序。编制一程序模拟该停车场的管理。(2) 实现要求:要求程序输出每辆车到达后的停车位置(停车场或便道上),以及某辆车离开停车场时应交纳的费用和它在停车场内停留的时间。(2) 实现提示:汽车的模拟输入信息格式可以是:(到达/离去,汽车牌照号码,到达/离去的时刻)。例如,(’A’,1,5)表示1号牌照车在5时刻到达,而(’D’,5,20)表示5号牌照车在20时刻离去。整个程序可以在输入信息为(’E’,0,0)时结束。本题可用顺序存储结构和链式存储结构来实现。本人的一个数据结构课程设计(用C++源码实现,供大家学习参考之用,有不妥之处望指正)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值