POJ 3903 Status List (LIS,O(nlogn))

LIS:Longest Increasing Subsequence 最长上升子序列

昨天用O(n^2)的方法做了HDU的导弹题,同样的,求LIS还有O(nlogn)的优化方法。

在这里,我们用sub保存一个最长上升子序列,top表示其长度。我们要做的就是让top尽可能的大。

算法:

每次输入一个数x,判断它和sub顶部的元素大小关系。

if x = sub[top] then

  sub[++top] <- x

else

  sub[第一个比x大的元素位置] <- x

于是,这变得有些不像DP了。而查找第一处比x大的元素位置,又可以使用二分法优化,于是整体的复杂度就为O(nlogn)了。

援引百度知道lydrainbowcat的解释:

整体的理解难点在理解sub是单调的,我们可以想,随着长度的增长,sub[top]中的元素会变小,为什么? 因为在最长不上升子序列中,不下降就可以意味这下降,下降得越多,就是top越大,当然sub[top]就越小

 

给出我的代码:

 1 #include <iostream>
2 using namespace std;
3
4 const int MAXN = 100005;
5 int num, sub[MAXN];
6
7 int main()
8 {
9 int n, top;
10 while(cin >> n)
11 {
12 sub[0] = -1; //考虑到第一个元素可能是0
13 top = 0;
14 for(int i = 0; i < n; i++)
15 {
16 cin >> num;
17 if(num > sub[top])
18 {
19 sub[++top] = num;
20 }
21 else
22 {
23 //此处是二分优化
24 int high = top, low = 1, mid;
25 while(low <= high)
26 {
27 mid = (high + low) / 2;
28 if(num > sub[mid])
29 {
30 low = mid + 1;
31 }
32 else
33 {
34 high = mid - 1;
35 }
36 }
37 sub[low] = num;
38 }
39 }
40 cout << top << endl;
41 }
42 return 0;
43 }


另外感谢一下slyar,这个将sub[0]置为-1的想法是从他那看到的。另外,slyar的一些文章很不错,大家可以去翻翻(广告一下~)。

posted @ 2012-03-08 19:44  dgsrz  阅读(393)  评论(0编辑  收藏  举报