• 最大上升序列算法


    最长上升子序列问题:

    给出一个由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
    ", 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>
    #include <string.h>
    int b[100100];
    int a[100111];
    int f(int a[], int n)
    {
    
        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-1;
                        else
                            z = mid+1;
                    }
                    b[z] = a[i];
                }
            }
        return t;
    }
    int main()
    {
    
        int n, i, k, j;
        scanf("%d", &n);
        for(i=0;i<n;i++)
            scanf("%d", &a[i]);
        printf("%d
    ", f(a, n));
        return 0;
    }
    O(nlogn)

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

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

    poj:3903 http://poj.org/problem?id=3903(要用nlogn算法)

  • 相关阅读:
    自我介绍
    软工第一次编程作业
    软件定义网络第一次作业
    软工个人总结
    实验 7: OpenDaylight 实验——Python 中的 REST API 调用
    实验 6:OpenDaylight 实验——OpenDaylight 及 Postman 实现流表下发
    软工结对编程作业
    实验 4 : Open vSwitch 实验——Mininet 中使用 OVS 命令
    软件定义网络第三次作业
    软件定义网络第二次作业
  • 原文地址:https://www.cnblogs.com/Noevon/p/5685975.html
Copyright © 2020-2023  润新知