基础之基础之中的基础,然而很简单
简单的动态规划,最长上升子序列 LIS(Longest Increasing Subsequence)
dp[i]表示第i个数结尾的最长上升子序列的长度
初始是dp[i]=1;seg[i]储存第i个数;
求第 i 个的最长LIS 就是求 max j (< i)的LIS加上 1,
状态转移方程dp[i]=max(dp[i],dp[j]+1);
如果seg[j]<seg[i]并且j<i的话,就更新,取最大值;
这个题用的是值,每次更新的时候取值最大的,
1 # include <cstdio> 2 # include <iostream> 3 # include <algorithm> 4 # include <cstring> 5 using namespace std; 6 7 int n; 8 const int maxn=1e3+5; 9 int dp[maxn],seg[maxn]; 10 11 int main(){ 12 while(scanf("%d",&n)!=EOF&&n){ 13 for(int i=0;i<n;i++) 14 scanf("%d",&seg[i]); 15 int ans=0; 16 for(int i=0;i<n;i++){ 17 dp[i]=seg[i]; 18 for(int j=0;j<i;j++){ 19 if(dp[i]<dp[j]+seg[i]&&seg[j]<seg[i]){ 20 dp[i]=max(dp[i],dp[j]+seg[i]); 21 } 22 } 23 ans=max(ans,dp[i]); 24 } 25 printf("%d ",ans); 26 } 27 return 0; 28 }
上面的这个时间复杂度(n*n),
还有一种时间复杂度为(nlogn)的做法,用一个栈来维护一个从大到小的数列
对于当前的数 x 如果大于栈顶的元素的话,就加入栈,
否则的话就在当前的栈内二分查找第一个大于或等于 x 的数,并替换它,
1 int a[maxn]; 2 int stack[maxn];//储存最大上升子序列的栈 3 int top;//栈顶 4 int l;//数组的长度 5 6 void solve(){ 7 top=0,stack[top]=-INF; 8 for(int i=1;i<=l;i++){ 9 int t=stack[top]; 10 if(a[i]>t) stack[++top]=t; 11 else { 12 int ls=0,rs=top;//二分搜索第一个大于等于a[i ]的元素 13 while(rs-ls>1){ 14 int mid=(rs+ls)>>1; 15 if(stack[mid]>=t) rs=mid; 16 else ls=mid; 17 } 18 stack[rs]=t; 19 } 20 } 21 cout<<top<<endl;//最后所求的top就是最长上升子序列 22 }