最长上升子序列

来源:互联网 发布:java分布式模块 编辑:程序博客网 时间:2024/06/08 15:19
最长上升子序列 (Longest Increasing Subsequence, 常简称为 LIS) 是动态规划解决的一个经典问题。  我们先讲一下子序列是什么。一个数组的子序列就是从里面选出一些元素,并将他们保持原有的先后顺序排列。比如[1, 2, 3, 4, 5]的子序列有[1, 3, 5]、[3, 4],而[1, 5, 3]则不是这个数组的子序列。  这里多介绍一下,还有一个容易与子序列混淆的概念:子串。子串是指从一个数组中选出连续的一个或多个元素,并且保持他们原有的顺序。子串一定是子序列,比如前面的子序列[3, 4]就是子串,但[1, 3, 5]不是子串,因为这三个元素在原数组中并不是连续的。  一句话总结他们的区别,就是子序列可以不连续,而子串必须连续。  上升子序列是指子序列Ai中满足 A1 < A2 < ... < An,也就是后面的元素一定比前面的元素大,比如(1, 3, 5)是上升子序列,(1, 3, 3)和(1, 4, 3)都不是。现在来跟我一起解决最长上升子序列的问题吧!(o・・o)/  输入格式:  第一行一个整数n(1 ≤ n ≤ 100),表示序列的长度。  第二行 n 个整数,表示序列中的每个元素。  输出格式:  输出只有一行,为最长上升子序列的长度
序列  1 5 2 3 4
两个for循环,num[j]是num[i]的内层从第i=1个开始,第一次循环j=1;由于num[i]与num[j]是同一个所以马上退出内层循环。  result=max(dp[i], result);这里更新最大子序列的值。i=2, j=1:在num[1] < num[2],所以执行dp[2] = max(dp[1]+1, dp[2]).这句代码就是状态转移。继续j++,不符合条件就退出内层循环,从而进入第三次循环。result=max(dp[i], result);这里更新最大子序列的值。i=3,j=1;内层第一次循环,j=1时,num[1] < num[3],所以dp[3]=max(dp[1]+1, dp[3]);j=2时,num[2]>num[3],不执行状态转移的代码,然后j++,j=3,不符合条件,退出内层循环。 result=max(dp[i], result);这里更新最大子序列的值。i=4, j=1时,num[1]<num[4],所以dp[4]]=max(dp[1]+1, dp[4]); j=2,   num[2]>num[4], 不执行状态转移的代码   j=3,  num[3]<num[4], 所以dp[4]=max(dp[3]+1,dp[4])   j=4,退出内层循环。result=max(dp[i], result);这里更新最大子序列的值。i=5, j=1时,num[1]<num[5],所以dp[5]=max(dp[1]+1, dp[5]); j=2,   num[2]>num[5], 不执行状态转移的代码   j=3,  num[3]<num[5], 所以dp[5]=max(dp[3]+1,dp[5])   j=4,  num[4]<num[5], 所以dp[5]=max(dp[4]+1,dp[5])result=max(dp[i], result);这里更新最大子序列的值。然后退出外层循环。最后输出result即可。#include <iostream>#include <cstdio>using namespace std;int n, dp[101], num[101], result = 0;int main() {    scanf("%d", &n);    for (int i = 1; i <= n; ++i) {        scanf("%d", &num[i]);    }      for(int i = 1; i <= n; i++)    {        dp[i] = 1;        for(int j = 1; j < i; j++)        {            if(num[j] < num[i])            {               dp[i] = max(dp[j]+1, dp[i]);            }        }        result = max(result, dp[i]);    }    printf("%d\n", result);    return 0;}

0 0