L2-014. 列车调度
Standard
火车站的列车调度铁轨的结构如下图所示。
Figure
两端分别是一条入口(Entrance)轨道和一条出口(Exit)轨道,它们之间有N条平行的轨道。每趟列车从入口可以选择任意一条轨道进入,最后从出口离开。在图中有9趟列车,在入口处按照{8,4,2,5,3,9,1,6,7}的顺序排队等待进入。如果要求它们必须按序号递减的顺序从出口离开,则至少需要多少条平行铁轨用于调度?
输入格式:
输入第一行给出一个整数N (2 <= N <= 10
5
),下一行给出从1到N的整数序号的一个重排列。数字间以空格分隔。
输出格式:
在一行中输出可以将输入的列车按序号递减的顺序调离所需要的最少的铁轨条数。
输入样例:
9 8 4 2 5 3 9 1 6 7
输出样例:
4
思路:
分析题目,可以得出这样的策略:
每进一辆车,将其添加到已有轨道上队尾编号大于它的并且编号尽量小的那个轨道上。如果无法添加,则新开一条轨道。
这样可以保证出队序列合法并且最大化利用空间。
做法1:我直接用queue模拟每条轨道的队列。并用一个vis数组记录进站的列车,用一个变量out记录当前可以出站的最大编号。这样出站时可以直接出站一段连续的列车。但是内存超限。
做法2:经过进一步分析,发现我们只需要记录每条轨道的队尾编号即可,因为队列是单调的。并且因为这个特性,出站时也不用考虑非队尾元素的出站,只需要考虑队尾元素是否出站,如果出站,则初始化这个位置即可。那么就可以用一个一维数组来代替queue数组了。但是有两组数据超时。
做法3:进一步抽象做法2。做法2超时在寻找大于u且尽量小的位置时用了两层循环。并且出站时也是两层循环。那么如果这些队尾元素也按照单调排列,那么就可以用二分查找插入的位置了,并且出站时也可大大减少循环的次数。于是可以用set容器来存储队尾元素,low_bounder进行二分查找。求每次入站size的最大值即可。
代码:
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<algorithm>
#include<set>
using namespace std;
#define inf 1<<29
int n;
set<int> s;
bool vis[100005];
int main()
{
scanf("%d",&n);
memset(vis,0,sizeof vis);
s.clear();
int out=n,cnt=0;
for(int i=0;i<n;i++)
{
int u;
scanf("%d",&u);
vis[u]=1;
set<int>::iterator it;
it = s.lower_bound(u);
if(it!=s.end()) s.erase(it);
s.insert(u);
int k=s.size();
cnt=max(cnt,k);
if(u==out)
{
while(out>0 && vis[--out]);
set<int>::iterator it;
for(it=s.begin();it!=s.end();it++)
{
if((*it)==out) break;
}
while(it!=s.end()) s.erase(it);
}
}
printf("%d\n",cnt);
return 0;
}