动态规划入门 COGS1398 最长上升子序列

来源:互联网 发布:linux shell 打印变量 编辑:程序博客网 时间:2024/06/03 14:31
1398. 最长上升子序列

★   输入文件:lis1.in   输出文件:lis1.out   简单对比
时间限制:1 s   内存限制:256 MB

【题目描述】

 

设有整数序列A[1],A[2],A[3],…,A[m],若存在下标i1<i2<i3<…<in,且A[i1]<A[i2]<A[i3]<…<A[in],则称 序列A[1],A[2],A[3],…,A[m]中有长度为n的上升子序列A[i1] , A[i2] ,A[i3] ,…,A[in]。

请编程计算指定序列的最长上升子序列长度。

 

【输入格式】

第一行一个正整数n(n<1001),表示序列中整数个数;

第二行是空格隔开的n个整数组成的序列。

【输出格式】

一个正整数,表示输入文件中整数序列的最长上升子序列的长度。

【样例输入】

  7

1 7 3 5 9 4 8

【样例输出】

4

 

【样例说明】

 序列(1,7,3,5,9,4,8)最长上升序列有:(1,3,5,9),(1,3,5,8),(1,3,4,8),他们长度为4。
方程为f(i)=max{f(j)}+1(b

j

<b

i

且i<j)

 

这个题重在优化
首先先贴LIS代码
注意要赋到f[]数组初值(某小受就没有)
 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 using namespace std; 6  7 int n; 8 int in[10010],f[10010]; 9 int ans;10 11 int main(){12     scanf("%d",&n);13     for(int i=1;i<=n;i++) scanf("%d",&in[i]),f[i]=1;14     for(int i=2;i<=n;i++){15         for(int j=1;j<i;j++)16             if(in[i]>in[j]) f[i]=max(f[i],f[j]+1);17         ans=max(ans,f[i]);18     }19     printf("%d",ans);20     return 0;21 }

 

单调栈优化

从前向后扫描序列列,维护一个单调栈

插⼊入一个数时,我们在h[] 中二分出一个位置i,使得h[i]<a[k+1]<=h[i + 1],令h[i+1]=a[k + 1] 即可

 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6  7 int n; 8 int num[10010]; 9 int top;10 int tmp;11 12 void add(int t){13     if(t>num[top]) num[++top]=t;14     else{15         int ll=1;16         int rr=top;17         int mid;18         while(ll<=rr){19             mid=(ll+rr)>>1;20             if(t>num[mid]) ll=mid+1;21             else rr=mid-1;//注意-1和+122         }23         num[ll]=t;24     }25     return;26 }27 28 int main(){29     scanf("%d",&n);30     num[0]=-1;31     for(int i=1;i<=n;i++) scanf("%d",&tmp),add(tmp);32     printf("%d",top);33     return 0;34 } 

 

树状数组优化

数组离散化并用树状数组维护前缀最大值

 1 //实为最长上升子序列  2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7  8 int n; 9 int in[10010],val[10010];10 int len;11 int b[10010];//b[i]以数字i结尾的子序列最长可以为的值 12 //扫描到in[k]这个位置时,b[i]中只有b[a[k]]会改变13 //b[a[k]]=max(b[i]+1|i<a[k])  14 int ans,temp;15 16 void add(int v,int pos){17     for(int i=pos;i<=len;i+=i&(-i)) b[i]=max(v,b[i]);18     return; 19 }20 21 int ask(int pos){22     int t=0;23     for(int i=pos;i;i-=i&(-i)) t=max(t,b[i]);24     return t;25 } 26 27 int main(){28     scanf("%d",&n);29     for(int i=1;i<=n;i++) scanf("%d",&in[i]),val[i]=in[i];30     sort(val+1,val+n+1);31     len=unique(val+1,val+n+1)-val;//去重 保证最长上升32     memset(b,0,sizeof(b));33     ans=1;34     for(int i=1;i<=n;i++){35         in[i]=lower_bound(val+1,val+len+1,in[i])-val+1;//离散化???高大上 36         temp=ask(in[i]-1)+1;37         ans=max(ans,temp);38         add(temp,in[i]);39     }40     printf("%d",ans);41 }

 

线段树优化

可以用树状数组优化,那么显然可用线段树

然而我码了2K挂掉了,以后再补

 

原创粉丝点击