一、题目
火车站的列车调度铁轨的结构如下图所示。
两端分别是一条入口(Entrance)轨道和一条出口(Exit)轨道,它们之间有 N 条平行的轨道。每趟列车从入口可以选择任意一条轨道进入,最后从出口离开。在图中有9趟列车,在入口处按照{8,4,2,5,3,9,1,6,7}的顺序排队等待进入。如果要求它们必须按序号递减的顺序从出口离开,则至少需要多少条平行铁轨用于调度?
输入格式:
输入第一行给出一个整数 N (2 ≤ N ≤105 ),下一行给出从1到 N 的整数序号的一个重排列。数字间以空格分隔。
输出格式:
在一行中输出可以将输入的列车按序号递减的顺序调离所需要的最少的铁轨条数。
输入样例:
9
8 4 2 5 3 9 1 6 7
输出样例:
4
二、方法1
1、思路
本质上就是最长上升子序列问题(LIS),所以第一想法就是贪心。
以样例为例:8 4 2 5 3 9 1 6 7
四个序列分别为:8 4 2 1,5 3,9 6,7
用数组模拟栈,每次比较数字与栈顶的大小:
- 若大则进栈,开辟新轨道;
- 若小则二分查找,更新栈顶。
2、代码
#include<stdio.h>
#define max 100010
int n;
int i, j, k; // 遍历
int num = 1; // 铁轨条数
int a[max], dp[max]; // a->存数,dp->栈
int search(int a[], int aSize, int key);
int main()
{
scanf("%d", &n);
for (i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
}
dp[1] = a[1];
for (i = 2; i <= n; i++)
{
// 每遇到一个比栈顶元素大的数,就放进栈里,
if (a[i] >= dp[num])
dp[++num] = a[i];
// 遇到比栈顶元素小的就二分查找前边的元素
else
{
// 返回第一个大于等于key的元素
j = search(a, num, a[i]);
// 更新栈顶元素
dp[j] = a[i];
}
}
printf("%d\n", num);
return 0;
}
int search(int a[], int aSize, int key)
{
int left = 1, right = aSize, mid;
while (left <= right)
{
mid = left + (right - left) / 2; // 防止栈溢出
if (dp[mid] > key)
right = mid - 1;
else
left = mid + 1;
}
return left;
}