码迷,mamicode.com
首页 > 编程语言 > 详细

最大上升序列算法

时间:2016-07-19 20:32:58      阅读:215      评论:0      收藏:0      [点我收藏+]

标签:

最长上升子序列问题:

给出一个由n个数组成的序列x[1..n],找出它的最长单调上升子序列。即求最大的m和a1,
a2……,am,使得a1<a2<……<am且x[a1]<x[a2]<……<x[am]。

1.动态规划求解思路分析:(O(n^2))

经典的O(n^2)的动态规划算法,设a[i]表示序列中的第i个数,b[i]表示从1到i这一段中以i结尾的最长上升子序列的长度,初始时设F[i] = 0(i = 1, 2, ..., len(a))。则有动态规划方程:b[i] = max{1, b[j] + 1} (更新,最大的加一)(j = 1, 2, ..., i - 1, 且a[j] < a[i])。

令a[i]表示输入第i个元素,b[i]表示从a[1]到a[i]中以a[i]结尾的最长子序列长度。对于任意的0 <  j <= i-1,如果a(j) < a(i),则a(i)可以接在a(j)后面形成一个以a(i)结尾的新的最长上升子序列。对于所有的 0 <  j <= i-1,我们需要找出其中的最大值。

DP状态转移方程:

b[i] = max{1, b[j] + 1} (j = 1, 2, 3, ..., i-1 且 a[j] < a[i])

解释一下这个方程,i, j在范围内:

如果 a[j] < a[i] ,则b[i] = b[j] + 1

如果 a[j] >= a[i] ,则b[i] = 1

技术分享
 1 #include <stdio.h>
 2 int a[10000],b[10000];
 3 int main()
 4 {
 5     int n, i, j, max;
 6     scanf("%d", &n);
 7     for(i=0;i<n;i++)
 8     {
 9         scanf("%d", &a[i]);
10         b[i] = 1;
11     }
12     for(i=n-1;i>=0;i--)
13         for(j=i;j<n;j++)
14             if(a[i]<a[j] && b[j]+1>b[i])
15                 b[i] = b[j]+1;
16     for(max=1,i=0;i<n;i++)
17         if(max < b[i])
18             max = b[i];
19         printf("%d\n", max);
20     return 0;
21 }
O(n*n)

 

2.贪心+二分查找:(O(nlogn))
开辟一个栈,每次取栈顶元素s和读到的元素a做比较,如果a>s,则加入栈;

如果a<s,则二分查找栈中的比a大的第1个数,并替换。

最后序列长度为栈的长度。  
这也是很好理解的,对x和y,如果x<y且E[y]<E[x],用E[x]替换  E[y],此时的最长序列长度没有改变但序列Q的‘‘潜力‘‘增大。  
举例:原序列为1,5,8,3,6,7  
栈为1,5,8,此时读到3,则用3替换5,得到栈中元素为1,3,8

再读6,用6替换8,得到1,3,6

再读7,得到最终栈为1,3,6,7

最长递增子序列为长度4。 

用数组模拟

技术分享
#include <stdio.h>
int f(int a[], int n)
{
    int b[10100];
    int t, i, z ,y, mid;
    b[t=1] = a[0];
    for(i=1;i<n;i++)
        {
            if(a[i]>b[t])
                b[++t] = a[i];
            else
            {
                z=0;y=t;
                while(z<y)
                {
                     mid = (z+y)/2;
                    if(b[mid] > a[i])
                        y = mid;
                    else
                        z = mid+1;
                }
                b[z] = a[i];
            }
        }
    return t;
}
int main()
{
    int a[100011];
    int n, i, k;
    scanf("%d", &n);
    for(i=0;i<n;i++)
        scanf("%d", &a[i]);
    printf("%d\n", f(a, n));
    return 0;
}
O(nlogn)

推荐一些最大上升序列的题

poj:2533 http://poj.org/problem?id=2533

 题解:

最大上升序列算法

标签:

原文地址:http://www.cnblogs.com/Noevon/p/5685975.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!