java火车抢票_【刷题笔记】火车购票-----java方案

问题描述

请实现一个铁路购票系统的简单座位分配算法,来处理一节车厢的座位分配。

假设一节车厢有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 1) 购2张票,得到座位1、2。

6 7 8 9 10 2) 购5张票,得到座位6至10。

11 12 13 14 3) 购4张票,得到座位11至14。

3 4 4) 购2张票,得到座位3、4。

---------------------------------------------------------------请思考的分割线----------------------------------------------------------------------

读者看到这里的时候,想必心里已经有自己的想法了。无论可行性如何,有想法才是最重要的。接下来我们来看一下这个问题的解决思路吧。(个人能力有限,所以贡献的算法也难免局限,如果大家有更好的想法,欢迎讨论)

首先,看到问题的时候第一思路是建立一个数组来记录100个座位的占用情况,对于每一次的购票行为,只需要对数组进行遍历,找到满足要求的位置并占用即可。当然这种方法的缺陷也很明显,每一次的购票行为都需要对数组进行遍历,而且由于每一排有5个座位的限制,所以在遍历的时候仍然要考虑连续的座位是否在同一排中,这无疑会增加算法的复杂性。

进一步想,既然题目的座位是20排,那我们可以直接选择二维数组作为我们记录占用情况的数据结构。针对二维数组而言,我们只需要按行遍历,对于每一行判断是否可以容纳本次的购票人数。这种方法的遍历情况跟上一个方法是一样的,优势在于每一次的子数组长度都是5,不需要另行判断。

上面的方法都局限在同一个问题,即对座位数组的反复遍历。尤其是对于那些已经占用的座位,每一次的遍历都是白白地消耗时间,如果,(敲黑板,重点来了)对于已经被占用的位置,我们可以减少访问,那么我们的运行时间就可以缩短!!!

针对上面的两种思路我们来进行改进,我们先从一维数组开始考虑(因为二维数组的想留给读者自己试验)。在购票过程中,我们会尽量地把同一批客户安排在连续的同一排座位。那么我们在每次安排座位的时候,在被占用的数组中标示连续占用的座位数,这样的话,在我们遍历的时候就可以直接利用这个数字跳过这段连续的区域,减少访问次数。

看完上面这段,读者可能对方法还是很疑惑。语言描述实在是不够直观,我们不妨看一下示意图。

5934ce1ba84f58d8f9520eaa6a2b5013.png

如果读者看图已经明白了原理,不妨先去实现一下。如果还是觉得抽象,我们就来细细地看图说话吧。

上图显示的就是示例中的购票过程,首先将数组seats初始化为0,表示座位空置。

第一次购票2张,占用位置(数组片段)是1、2,把seats[1]的数字置为2,表示由此开始的连续两个座位被占用。等到遍历数组时,在这个位置可以对下标进行+2操作,直接跳过这一段被占用的座位。

第二次购票是5张,从头开始遍历数组,访问第一个位置,被占用且数字为2,则跳转到1+2=3号位置,3号座位为0表示空置,但是3--5之间只有三个空位,不能容纳5个人,所以跳转到下一排,即6号位置,6号位满足要求,在此处落座并更改seats[6] = 5。

第三次购票是4张,依然从头开始,1号位非0,跳转至1+2=3号位;3号位为0,但是空间不足,跳转至6号位;6号位非0,跳转至6+5=11号位;11号位为0且空间足够,落座并更改seats[11] = 4。

第四次购票是2张,遍历过程如上,1号位非0,转至1+2=3号位;3号位为0且空间足够,落座并更改seats[3]=2。

到此为止,例程部分的购票已经结束。如果某次购票行为中发现没有足够的连续空位,就要选择散座,即重新从头开始遍历,并且每次只坐一个人。方法同上。

总结一下,在这个版本的算法中,我们合理利用了开辟的数组,记录了被连续占用的段落长度,从而减少了遍历的次数,好像已经前进了一步。但是这个算法仍然可能需要进行两次遍历,即第一次找不到连续座位然后重新找散座。因为题目中的要求是先尽量连续分配,失败则分配散座,所以两次遍历操作是难免的。

考虑到以上的情况,再来想一想能不能在遍历过程中再精简一些。

---------------------------------------------------------------请思考的分割线----------------------------------------------------------------------

仔细分析一下,上面的过程中对于每一排座位,是在发现空位之后才去判断空位数是否足够。从二维数组的角度考虑一下,如果每一行的第一个位置标示了这一排已经坐下的人数x,那么我们就可以很直接的通过5-x得到空余的座位。这样的话我们就不必要先跳转到空位,而可以直接判断是否在这一排落座,如果选择落座的话,则利用排首坐标+x跳转至座位。

相比之下,二维数组的情况跟一维是相似的,甚至更简单,我们在每一行的第一个位置记录下本行已经被占用的座位数,这样的话每次只需要访问seats[*][1]的数字,就可以得知该行是否可以坐并且可以直接找到空位,落座的时候也只需要让seats[*][1]加上本次坐下的人数。

PS:读者如果注意到上面seats[*][1]里的*,应该明白其实完全可以只用一个20位的数组解决。哇塞,进步好大啊!!问题不难,读者请动手试试吧。(注意,文中的数组起始下标是1,请根据实际情况修正)

PPS:俗话说得好,talk is cheap,show me the code。下面贴上对于一维数组的相对比较复杂的算法实现。大家试着实现其它的吧。

1 Scanner fin = newScanner(System.in); //有一些语句是为了对应提交题目的格式,读者自动选择有价值的部分参观2 int N =fin.nextInt();3

4 int [] seat = new int[100];5

6 for(int i=0;i 0){20 String cc = Integer.toString(++pos);21 System.out.print(cc + " ");22 num --;23 }24 }else{25 pos = 0;26 while(num > 0){27 if (seat[pos] == 0){28 String cc = Integer.toString(pos+1);29 System.out.print(cc + " ");30 seat[pos++] = 1;31 num--;32 }else{33 pos +=seat[pos];34 }35 }36 }37 System.out.println("");38 }

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值