PTAL2-014列车调度(二分法/Set集合)
两种方法解决该问题
火车站的列车调度铁轨的结构如下图所示。
两端分别是一条入口(Entrance)轨道和一条出口(Exit)轨道,它们之间有N条平行的轨道。每趟列车从入口可以选择任意一条轨道进入,最后从出口离开。在图中有9趟列车,在入口处按照{8,4,2,5,3,9,1,6,7}的顺序排队等待进入。如果要求它们必须按序号递减的顺序从出口离开,则至少需要多少条平行铁轨用于调度?
输入格式
输入第一行给出一个整数N
(2 ≤ N
≤ 1 0 5 10^5 105 ),下一行给出从1到N
的整数序号的一个重排列。数字间以空格分隔。
输出格式
在一行中输出可以将输入的列车按序号递减的顺序调离所需要的最少的铁轨条数。
输入样例
9
8 4 2 5 3 9 1 6 7
输出样例
4
思路剖析1
- 采用set,set可以将元素按照从小到大排序,并且set可以找到比某一个元素大的第一个元素的位置迭代器,取引号就是它的值。
- 这题就是将输入的那一串数放入轨道内,若出现要放的火车的序号大于该轨道的末尾火车序号,则需要重开轨道。
#include <algorithm>
#include <iostream>
#include <set>
using namespace std;
int railWay[100010];
set<int> s;
int main()
{int N;cin >> N;int count = 0;int i;for (i = 1; i <= N; i++){cin >> railWay[i];}s.insert(0);// 刚开始已经有个铁轨了for (i = 1; i <= N; i++){if ((*s.rbegin()) < railWay[i]){count += 1;// s.insert(railWay[i]);s.insert(railWay[i]);// cout << "另起炉灶count:" << count << ", pos:" << railWay[i] << endl;continue;}else{s.erase(*(s.upper_bound(railWay[i])));s.insert(railWay[i]);}}cout << count << endl;return 0;
}
思路剖析2
- 其实这题直接用数组存储每个轨道的队尾火车序号即可,不能插入就开轨道,能插入采用二分法找到大于且最接近目前要插入火车的序号的那个轨道,然后插入进去将该轨道的队尾火车序号变为当前的火车序号。
- 有一个点要注意,就是你在执行上述的过程时,存放每一个轨道队尾序号的数组是规律递增的。认真想想,插不进去了是因为这个序号比所有目前的队尾序号都大,然后二分法找第一个比他大的轨道,插入进去,此时刚插入的序号比之前的所有轨道的队尾序号都大!
// 太美妙了这个想法,竟然可以做到每一个铁轨的火车最小序号是递增的。
// 简述一下原理,首先每次往某一个铁轨上加火车,序号肯定是越来越小的(能加的情况),
// 若不能加,另开一个道,那么这个新的道肯定比原来那个道序号大,如果出现的能加的情况,那么肯定要找这个比当前这个火车的序号大的轨道,且是最接近的。
// 这样就又保证了插进去后,该轨道的最小序号肯定比他之前的轨道最小序列大!!!(序号不重复)
// 采用二分法找最接近的,因为每次找最接近且比他大的,最后l肯定会等于r,且在最接近且比他大的位置。#include <algorithm>
#include <iostream>
#include <set>
using namespace std;
int railWay[100010];
int minNum[100010];
set<int> s;
int main()
{int N;cin >> N;int i, j;int count = 1;int flag = 0;// int pos = 1;for (i = 1; i <= N; i++){cin >> railWay[i];}int maxRail = railWay[1];minNum[1] = maxRail;// s.insert(maxRail);int left = 0, right = 0, mid;// 刚开始已经有个铁轨了for (i = 2; i <= N; i++){flag = 0;if (minNum[count] < railWay[i]){count += 1;// s.insert(railWay[i]);minNum[count] = railWay[i];maxRail = railWay[i];// cout << "另起炉灶count:" << count << ", pos:" << railWay[i] << endl;continue;}left = 1, right = count;while(left<=right){mid = (left + right) / 2;if(minNum[mid]>railWay[i]){right = mid - 1;}else{left = mid + 1;}}minNum[left] = railWay[i];}cout << count << endl;return 0;
}