c++动态规划基础——最长上升子序列

这次博主带来的是动态规划的一道基础题——最长上升子序列
希望可以对比较迷茫的小伙伴带来帮助!
以下为题目

最长上升子序列:

描述

一个数的序列bi,当b1 < b2 < ... < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, ..., aN),我们可以得到一些上升的子序列(ai1, ai2, ..., aiK),这里1 <= i1 < i2 < ... < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8).

你的任务,就是对于给定的序列,求出最长上升子序列的长度。

输入
输入的第一行是序列的长度N (1 <= N <= 1000)。第二行给出序列中的N个整数,这些整数的取值范围都在0到10000。
输出
最长上升子序列的长度。
样例输入

7
1 7 3 5 9 4 8

样例输出

4

好的,不多说,直接切入正题,首先确定思路。

  1. 想法
    对于这样的一道题,用贪心是无法解决的,因为结尾最大的子序列不一定就是最长的子序列。如:1 9 3 4 。贪心只可以看到1 9,结果不能找到1 3 4。对于这道题,我们可以用动态规划(DP)。

  2. 思路
    动态规划的关键在于定义数组的含义和“状态转移方程式”。这里我们可以定义一个数组 a[i] 来存数列,再定义 F[i] 用来表示 末尾 为 a[i] 的最长上升子序列。这句话非常重要!

  3. 状态转移方程式
    当 a[i]>a[j] 时,F[i]=max(F[j]+1,F[i]); 这里的max为取较大值,也就是F[i]为它本身和 F[j]+1 中较大的一个。有一个问题:F[i] 为什么要和自己比较呢,因为在循环中,F[i] 可能赋过很多次值。

    当 a[i]<=a[j]时, F[i]就不能变,因为 a[i] 不能接在 a[j] 后面。

    最后再在末尾为 1,2,3,…,n 的最长上升子序列中找到最长的那一个既是正确答案!

  4. 实现
    这里就直接给代码了:

#include
#include    //这个头文件可以使用max(,),*max_element(,)
using namespace std;    //它们的含义分别是:求两者最大;求数组最大
int n,a[1002],f[1002];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);   //输入
        f[i]=1;              //以第i个数为末尾的上升序列最初长度为1
    }
    for(int i=1;i<=n;i++)         //枚举i的位置
        for(int j=1;j//在i的前面找j的位置
            if(a[i]>a[j]) //如果满足条件,则第i个数可以放在j后边
                f[i]=max(f[j]+1,f[i]);//取较大的一种再放
    printf("%d",*max_element(f+1,f+n+1));//从 F[1]到F[n] 找最大值
    return 0;
}

那么这一道题就做完了!
但是这道题也有许多“变式”,例如:最长下降子序列,最长公共上升子序列……
这道题作为一道基础也隐藏在许多题目中,如:拦截导弹,渡轮问题等。
所以一定要把这道题了解清楚,才可以在更多的领域取得更好的成绩啊!

你可能感兴趣的:(动态规划)