zoukankan      html  css  js  c++  java
  • 动态规划入门 COGS1398 最长上升子序列

    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和+1
    22         }
    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挂掉了,以后再补

  • 相关阅读:
    正向代理/反向代理理解、Nginx概述、安装及配置详解
    项目部署问题:xftp无法连接服务器、Nginx403 Forbidden解决、nginx反向代理解决前端跨域问题
    Vue上传文件:ElementUI中的upload实现
    理解Vue的计算属性
    今天在CSDN看懂这个帖子,也是我的困惑,记录一下(过了三十的码农,你选择的是哪个,说出你的想法)
    WCF IIS上部署服务
    [转]WCF RESTful service and WebGrid in ASP.NET MVC 5
    WCF 与其它技术的比较
    Visual Studio Debug和Release的区别及obj的作用
    C# Json格式字符串
  • 原文地址:https://www.cnblogs.com/zwube/p/6790767.html
Copyright © 2011-2022 走看看