【CCF】201609-2火车购票

原文详见:https://blog.csdn.net/tigerisland45/article/details/54798869

试题编号: 201609-2
试题名称: 火车购票
时间限制: 1.0s
内存限制: 256.0MB
问题描述
  请实现一个铁路购票系统的简单座位分配算法,来处理一节车厢的座位分配。
  假设一节车厢有20排、每一排5个座位。为方便起见,我们用1到100来给所有的座位编号,第一排是1到5号,第二排是6到10号,依次类推,第20排是96到100号。
  购票时,一个人可能购一张或多张票,最多不超过5张。如果这几张票可以安排在同一排编号相邻的座位,则应该安排在编号最小的相邻座位。否则应该安排在编号最小的几个空座位中(不考虑是否相邻)。
  假设初始时车票全部未被购买,现在给了一些购票指令,请你处理这些指令。
输入格式
  输入的第一行包含一个整数n,表示购票指令的数量。
  第二行包含n个整数,每个整数p在1到5之间,表示要购入的票数,相邻的两个数之间使用一个空格分隔。
输出格式
  输出n行,每行对应一条指令的处理结果。
  对于购票指令p,输出p张车票的编号,按从小到大排序。
样例输入
4
2 5 4 2
样例输出
1 2
6 7 8 9 10
11 12 13 14
3 4
样例说明
  1) 购2张票,得到座位1、2。
  2) 购5张票,得到座位6至10。
  3) 购4张票,得到座位11至14。
  4) 购2张票,得到座位3、4。
评测用例规模与约定
  对于所有评测用例,1 ≤ n ≤ 100,所有购票数量之和不超过100。

解题思路
用数组或是map存储数据,数组会导致重复搜索,map逻辑稍微复杂些。下面是用map的解法,是我看了某大佬的解法之后,给它做了一个详细的注释,需要理解的地方都有说明。要考虑到同排分配和多排分配的情况,其输出是不同的。

首先了解一下map的大致作用:
【CCF】201609-2火车购票_第1张图片
下面是大佬的代码以及注释:

#include
#include 

using namespace std;

const int N=20;
const int NUM=5;
int main()
{
	map<int,int>m;
	int n,v,start,end;
	
	//初始化火车票 剩余张数 
	for(int i=1;i<=N;i++)
	 m[i]=NUM;
	
	//输入操作次数 
	cin>>n;
	for(int i=1;i<=n;i++){
	//输入购买张数 
		cin>>v;
		
	//一边输入一边分配
	// 同一排分配 
	for(map<int,int>::iterator it=m.begin();it!=m.end();it++)
	{
		//这一排的剩余票数大于或等于要购买的票数
		if(it->second>=v)
		{
			//计算出 分配座位的 起始位置 和 结束位置 的座位编号 
			start = (it->first-1)*NUM + (NUM-it->second+1);
			end = start + v -1;
			//依次输入分配到的座位编号 
			for(int j=start;j<=end;j++)
			{
				
			// 换行从第一个位置输出
			 if(j!=start)
			   cout<<" ";
			   cout<<j; 	
			}
			cout<<endl;
			
			//对于已经分配完毕的排,删除
			//该排的余票数量刚好与要分配的票数相等 
			if(it->second==v)
			 m.erase(it); 
			 else
			 it->second=it->second-v;
			 
			 //表示分配完成跳出本次循环
			 //没有这条语句会运行超时 
			 v=0;
			 break;		  
		} 
	} 
	
  	//多排分配车票
  	
	// 用于标记第一个输出 
	//是在分配过的排的基础上再分配 
	  bool nofirstflag=false;
	  
	  while(v>0)
	  {
	  	for(map<int,int>::iterator it=m.begin();it!=m.end();it++)
		{
		  	if(it->second>=v){
		  		start=(it->first-1)*NUM+(NUM-it->second+1);
		  		end=start+v-1;
		  		
		  		for(int j=start;j<=end;j++){
		  			
		  			if(nofirstflag)
		  			cout<<" ";
		  			cout<<j;
		  			
		  			nofirstflag=true;
				  }
				  //票分配完的排,删除 
				  if(it->second==v)
				   m.erase(it);
				   else
				   it->second=it->second-v; 
				   
				   v=0;
				   break; 
			  }
			  // 某一排的票数不够需要分配到另一排 
			  else{
			  	
			  	start=(it->first-1)*NUM+(NUM-it->second+1);
				  end=start+it->second-1;
				  for(int j=start;j<=end;j++)
				  {
				  	if(nofirstflag)
				  	cout<<" ";
				  	cout<<j;
				  	nofirstflag=true; 
				  }
				  //还需要被分配的票数 
				  v=v-it->second;
				  m.erase(it);  
			  }
		} 
		cout<<endl;
	  } 	
	}
	return 0;
} 

用数组存储可能会容易理解些,数组在某种程度上也可以化为map。如图存储数据:
【CCF】201609-2火车购票_第2张图片
下面是通过用数组存储的满分代码:

#include
using namespace std;

const int N=20;
const int NUM=5;
int main()
{
	int p[N];//存储每一排的余票数量
	int start,end,v;
	for(int i=1;i<=N;i++)
	 p[i]=NUM;
	 
	 int n;
	 cin>>n;
	 
	while(n--)
	{
		cin>>v;
		
		for(int i=1;i<=N;i++)
		{
			if(p[i]>=v)
			{
				start=(i-1)*NUM+NUM-p[i]+1;
				end=start+v-1;
				for(int j=start;j<=end;j++)
				{
				if(j!=start)
				  cout<<" ";
				  cout<<j;	
				}
			  cout<<endl;
			  	
			  p[i]=p[i]-v;
			 cout<<"p[i]"<<p[i]<<" i="<<i<<endl;
			  v=0;
			  break; 
			}
		}
		bool nofirstflag=false;
		while(v>0)
		{
			for(int i=1;i<=N;i++)
		  {
			if(p[i]>=v)
			{
				start=(i-1)*NUM+NUM-p[i]+1;
				end=start+v-1;
				
				for(int j=start;j<=end;j++)
				{
					if(nofirstflag)
					cout<<" ";
					cout<<j;
					nofirstflag=true;	
				}
				p[i]=p[i]-v;
				cout<<"p[i]"<<p[i]<<" i="<<i<<endl;
				v=0;
				break;
			}
			else
			{
				start=(i-1)*NUM+NUM-p[i]+1;
				end=start+p[i]-1;
				for(int j=start;j<=end;j++)
				{
					if(nofirstflag)
					cout<<" ";
					cout<<j;
					nofirstflag=true;
				}
				v=v-p[i];
				cout<<"p[i]"<<p[i]<<" i="<<i<<endl;
				p[i]=0;
			}
		  }
		}	
	}
	return 0; 	 
}

你可能感兴趣的:(CCF认证考题)