【刷题笔记】火车购票-----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,不需要另行判断。
上面的方法都局限在同一个问题,即对座位数组的反复遍历。尤其是对于那些已经占用的座位,每一次的遍历都是白白地消耗时间,如果,(敲黑板,重点来了)对于已经被占用的位置,我们可以减少访问,那么我们的运行时间就可以缩短!!!
针对上面的两种思路我们来进行改进,我们先从一维数组开始考虑(因为二维数组的想留给读者自己试验)。在购票过程中,我们会尽量地把同一批客户安排在连续的同一排座位。那么我们在每次安排座位的时候,在被占用的数组中标示连续占用的座位数,这样的话,在我们遍历的时候就可以直接利用这个数字跳过这段连续的区域,减少访问次数。
看完上面这段,读者可能对方法还是很疑惑。语言描述实在是不够直观,我们不妨看一下示意图。
如果读者看图已经明白了原理,不妨先去实现一下。如果还是觉得抽象,我们就来细细地看图说话吧。
上图显示的就是示例中的购票过程,首先将数组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。下面贴上对于一维数组的相对比较复杂的算法实现。大家试着实现其它的吧。
- Scanner fin = new Scanner(System.in); //有一些语句是为了对应提交题目的格式,读者自动选择有价值的部分参观
- int N = fin.nextInt();
- int [] seat = new int[100];
- for(int i=0;i<N;i++){
- int num = fin.nextInt();
- int pos = 0;
- while(pos < 100){
- if(seat[pos] == 0){
- if(pos%5 + num <= 5) break;
- pos = pos + 5 - pos%5;
- }else{
- pos += seat[pos];
- }
- }
- if(pos < 100){
- seat[pos] = num;
- while(num > 0){
- String cc = Integer.toString(++pos);
- System.out.print(cc + " ");
- num --;
- }
- }else{
- pos = 0;
- while(num > 0){
- if (seat[pos] == 0){
- String cc = Integer.toString(pos+1);
- System.out.print(cc + " ");
- seat[pos++] = 1;
- num--;
- }else{
- pos += seat[pos];
- }
- }
- }
- System.out.println("");
- }
【刷题笔记】火车购票-----java方案的更多相关文章
- 《Data Structures and Algorithm Analysis in C》学习与刷题笔记
<Data Structures and Algorithm Analysis in C>学习与刷题笔记 为什么要学习DSAAC? 某个月黑风高的夜晚,下班的我走在黯淡无光.冷清无人的冲之 ...
- Python 刷题笔记
Python 刷题笔记 本文记录了我在使用python刷题的时候遇到的知识点. 目录 Python 刷题笔记 选择.填空题 基本输入输出 sys.stdin 与input 运行脚本时传入参数 Pyth ...
- PTA刷题笔记
PTA刷题记录 仓库地址: https://github.com/Haorical/Code/tree/master/PTA/GPLT 两周之内刷完GPLT L2和L3的题,持续更新,包括AK代码,坑 ...
- PAT-甲级刷题笔记和总结
本帖主要记录一些自己在刷题过程中的一些笔记,包括: 1.常用的函数 2.STL中常用方法 3.常见错误 4.其他常用方法 5.刷题过程中的常见算法:https://www.cnblogs.com/M ...
- CCF201609-2 火车购票 java(100分)
试题编号: 201609-2 试题名称: 火车购票 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 请实现一个铁路购票系统的简单座位分配算法,来处理一节车厢的座位分配. 假设一 ...
- LeetCode刷题笔记 - 12. 整数转罗马数字
学好算法很重要,然后要学好算法,大量的练习是必不可少的,LeetCode是我经常去的一个刷题网站,上面的题目非常详细,各个标签的题目都有,可以整体练习,本公众号后续会带大家做一做上面的算法题. 官方链 ...
- 《剑指offer》刷题笔记
简介 此笔记为我在 leetcode 上的<剑指offer>专题刷题时的笔记整理. 在刷题时我尝试了 leetcode 上热门题解中的多种方法,这些不同方法的实现都列在了笔记中. leet ...
- 18.9.10 LeetCode刷题笔记
本人算法还是比较菜的,因此大部分在刷基础题,高手勿喷 选择Python进行刷题,因为坑少,所以不太想用CPP: 1.买股票的最佳时期2 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格. ...
- 剑指offer刷题笔记
删除链表中重复的结点:较难 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. 例如,链表1->2->3->3->4->4- ...
随机推荐
- fedora配置163为yum的源
一种方法: 1.下载 http://mirrors.163.com/.help/fedora-163.repo 和 http://mirrors.163.com/.help/fedora-updat ...
- WinForm下增加声音提示
在WinForm平台下播放声音,一般有两种方式:第一种是调用系统自带声音: [代码] 申明定义: [DllImport("kernel32.dll")] public static ...
- 如何基于Azure平台实现MySQL HA(方法论篇)
我们都知道,相较于传统的数据中心,Pulic cloud也有劣势,比如说数据库的HA,很多熟悉公有云平台的读者都知道,因为出于安全性性考虑以及一些技术条件的限制,很多本地数据中心的mysql HA方法 ...
- Easyui 设置datagrid 进入编辑状态,保存结束编辑
在datagrid中如何实现让一行进入编辑状态,修改数据后,保存信息呢? //点击列表变成文本框,进入可编辑状态 $(function () { var doc = $(document), tabl ...
- V4L2框架分析学习一
转载于http://www.techbulo.com/1193.html 1.概述 Video4Linux2是Linux内核中关于视频设备的内核驱动框架,为上层的访问底层的视频设备提供了统一的接口.凡 ...
- protobuf编译出错的解决方案(iOS,OSX)
protobuf 最近使用protobuf,变编译工具时遇上一点问题.现在附上解决方案 编译过程 完全参照 https://github.com/alexeyxo/protobuf-objc 编译出错 ...
- DataTable to Excel(使用NPOI、EPPlus将数据表中的数据读取到excel格式内存中)
/// <summary> /// DataTable to Excel(将数据表中的数据读取到excel格式内存中) /// </summary> /// <param ...
- java基础 swing编程实战
1. 实现金山词霸,点击左右收缩 效果图: exmaple code : /* * 词霸 * */ package demo7; import java.awt.*; import java.awt. ...
- Application对象、ViewState对象、分页展示--2017年1月4日
Application对象 存储 Application 变量 Application["application名称"] = "application的值"; ...
- 浅谈CPU和GPU的区别
导读: CPU和GPU之所以大不相同,是由于其设计目标的不同,它们分别针对了两种不同的应用场景.CPU需要很强的通用性来处理各种不同的数据类型,而GPU面对的则是类型高度统一的.相互无依赖的大规模数据 ...