题目:
给你一个长度为n的序列,让你找到最长上升子序列的长度.
分析:
这个是dp的经典问题,今天拿来重新学习一下。
如果按照贪心的想法,是很容易看到有问题的,比如一串数字 1,3,-3,-2,-1;
贪心的话从1开始,依次序列结尾的数字大的数,1,3长度为2,实际上LIS的长度为3
所以不能够用贪心来做,考虑dp。
dp的话,首先应该拆分问题:
要求n个,那么就找n-1个数的,n-2个数字的,找到这些状态之间的联系。
(其实对我来说这样来思考的话,我比较难找到状态方程)
不如从1个数字开始,假设dp[i]为当前数字结尾的序列的lis长度,那么对于前面以a[j]结尾的序列,如果a[i]>a[j],dp[i]=max(dp[j]+1);
这样就找到了转移关系,到这里之后应该注意到,我们只是把每一个数字结尾的lis找了出来,但这不是全局最优解,所以应该再找到最大的dp[i],才是最后的结果。
代码如下:
#include<iostream>
using namespace std;
int a[100001];
int dp[100001];
int main()
{
int i,j,n;
int ans=0;
cin>>n;
for(i=0;i<n;i++)
{
cin>>a[i];
dp[i]=1;
}
for(i=1;i<n;i++)
{
for(j=0;j<i;j++)
{
if(a[j]<a[i])
{
dp[i]=max(dp[i],dp[j]+1);
}
}
ans=max(ans,dp[i]);//一边计算dp[i]一边求出了最大dp[i]
}
cout<<ans<<endl;
return 0;
}
对于求最优解问题来说,先看下能不能贪心,不能,用dp.
对于dp问题,最重要的是拆分问题,问题怎么拆?我们假设什么量来表示,这个应该是解决问题的关键吧。