原题地址
http://poj.org/problem?id=2533
最长上升子序列问题:有一个长为n的数列,请求出这个序列中最长的上升子序列的长度。上升子序列指的是对任意的i < j都满足ai < aj的子序列(注意和子串的区别)。
解题思路
本题是最长上升子序列(Longest Increasing Sequence, LIS)的裸题,用动态规划求解最为方便。
O(n^2)的DP解法
定义dp[i]为以a[i]为结尾的LIS的长度。那么以a[i]结尾的上升子序列是:
- 只包含a[i]的序列(之前的a[j]都比它大)
- 在满足j < i 且a[j] < a[i]的以a[j]为结尾的上升子序列末尾,追加上a[i]
所以状态转移方程为:
dp[i] = max(1, dp[j]+1 | j < i and a[j] < a[i])
O(n*logn)的DP+二分解法
正在学习中…
AC代码
#include <iostream>
using namespace std;
int a[1005], dp[1005];
void solve(int n) //dp[i]:以a[i]为末尾的最长上升子序列长度
{
int LIS = 1;
for (int i = 0; i<n; ++i)
{
dp[i] = 1;
for (int j = 0; j<i; ++j)
if (a[j] < a[i]) //j<i且a[j]<a[i]时更新
{
dp[i] = max(dp[i], dp[j]+1);
LIS = max(LIS,dp[i]); //更新最长上升子序列长度
}
}
cout << LIS << endl;
}
int main()
{
ios::sync_with_stdio(false);
int n;
cin >> n;
for (int i = 0; i<n; ++i)
cin >> a[i];
solve(n);
return 0;
}