最长上升子序列:
一个序列有N个数:A[1],A[2],…,A[N],求出最长非降子序列的长度。
我们定义d(i),表示前i个数中以A[i]结尾的最长非降子序列的长度。
如果我们已经求出了d(1)到d(i-1),那么d(i)可以用下面的状态转移方程得到:
d(i) = max{1, d(j)+1},其中j<i,A[j]<=A[i]
如果我们要求的这N个数的序列是:
5,3,4,8,6,7
///简单找出最长上升子序列的个数
#include<cstdio>
#include<algorithm>
using namespace std;
int main()
{
int len[100]={0,5,3,4,8,6,7};
int dp[100],n,maxs;
n=6; ///假设n已赋值
maxs=-1;
for(int i=1;i<=n;i++)
{
dp[i]=1; ///自身成为一个长度为1的子序列
for(int j=1;j<=i;j++) ///在前i个数里找小于len[i]
{
if(len[j]<len[i]){
dp[i]=max(dp[i],dp[j]+1);
}
}
if(dp[i]>maxs)
maxs=dp[i];
}
printf("%d\n",maxs);
return 0;
}
这时最长上升子序列有多少个我们已经找出来了,但有没有想过怎么找出是哪几个子序列。
恕我水平有限,当有多组子序列都满足同样的最长上升子序列长度时,以下只能找出其一种情况,
例如
5 3 7 4 11 13
此序列很简单看出最长上升子序列长度为4;有两种不同的子序列,such as:5 7 11 13 与3 4 11 13.
在接下的代码中,我会讲解下如何找出其中一组序列,为什么我不涉略下怎么找出所有的可能的值呢?
答案是,一般题目不是那么神经的让你找出所有的子序列,一般是让你找出一组解就行了,
但倘若题目真的让你找出所有的解,
听君一句劝,拉上你朋友圈,在各大贴吧,论坛,微博......喷飞他。
假设一组数据: 5, 3 ,4, 8, 6, 7
我们来模拟一下,如图
i d[i] 存储上一级的位置
///找最长上升子序列
#include<cstdio>
#include<algorithm>
using namespace std;
int main()
{
int len[100]={0,5,3,4,8,6,7};
int dp[100],n,maxs,item,flag;
int book[100];
n=6; ///假设n已赋值
maxs=-1;
for(int i=1;i<=n;i++)
book[i]=i;
for(int i=1;i<=n;i++)
{
dp[i]=1; ///自身成为一个长度为1的子序列
for(int j=1;j<=i;j++) ///在前i个数里找小于len[i]
{
if(len[j]<len[i]){
if(dp[i]<=dp[j]+1) {dp[i]=dp[j]+1;
book[i]=j; } ///存储上一级的最长上升子序列的位置
}
}
if(dp[i]>maxs){
maxs=dp[i];
item=i; ///最长上升子序列的最后一个位置
}
}
printf("%d\n",maxs);
flag=0;
while(1){
printf("%d ",len[item]);
item=book[item];
if(item==book[item])
flag++; ///一直找,直到此判断成立。我们是从后往前找的,由上表可知
///当找到最初的位置时,此时的item和book[item]是相等的,
if(flag>1) break; ///所以这就是为什么要再定义个变量flag的原因了。
}
return 0;
}