zoukankan      html  css  js  c++  java
  • 求最长上升子序列和最长非下降子序列

      先放题:HDU 5256  http://acm.hdu.edu.cn/showproblem.php?pid=5256

       序列变换

       我们有一个数列A1,A2...An,你现在要求修改数量最少的元素,使得这个数列严格递增。其中无论是修改前还是修改后,每个元素都必须是整数。 
       请输出最少需要修改多少个元素。

       Input      第一行输入一个T(1T10)T(1≤T≤10),表示有多少组数据  

          每一组数据: 

          第一行输入一个N(1N105)N(1≤N≤105),表示数列的长度 

          第二行输入N个数A1,A2,...,AnA1,A2,...,An。 

          每一个数列中的元素都是正整数而且不超过106106。Output对于每组数据,先输出一行 
         Case #%d:  

         然后输出最少需要修改多少个元素;

         output:

    2
    2
    1 10
    3
    2 5 4
    Case #1:
    0
    Case #2:
    1

    该题思路:构造序列B[i]=A[i]-i;答案为序列总长度减去B的最长不下降子序列的长度;
    这题要求最长不下降子序列;
    刚开始写错了。。后来网上看到了一个nlog n的做法
    //最长不下降子序列nlogn  Song 
    
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    
    int a[40005];
    in
        t d[40005];
    
    int main()
    {
        int n;
        scanf("%d",&n);
        for (int i=1;i<=n;i++) scanf("%d",&a[i]);
        if (n==0)  //0个元素特判一下 
        {
            printf("0
    ");
            return 0;
        }
        d[1]=a[1];  //初始化 
        int len=1;
        for (int i=2;i<=n;i++)
        {
            if (a[i]>=d[len]) d[++len]=a[i];  //如果可以接在len后面就接上,如果是最长上升子序列,这里变成> 
            else  //否则就找一个最该替换的替换掉 
            {
                int j=upper_bound(d+1,d+len+1,a[i])-d;  //找到第一个大于它的d的下标,如果是最长上升子序列,这里变成lower_bound 
                d[j]=a[i]; 
            }
           }
        printf("%d
    ",len);    
        return 0;
    }

         (里面求最长上升子序列的也标注了)

    还有个n2的做法,应该只能处理少数数据

    #include<cstdio>
    #include<iostream>
    using namespace std;
    int num,n,a[1001],sum[1001];
    int main()
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
          {
              scanf("%d",&a[i]);
              sum[i]=1;
              for (int j=1;j<i;j++)
                if (a[j]<a[i]&&sum[j]>=sum[i])//如果a[j]比a[i]小并且第j个数的不下降序列比当前的长或相等
                  sum[i]=sum[j]+1;
              num=max(num,sum[i]);//判断当前段是否为最优
          }
        printf("%d",num);
    }

     然后是题目ac的代码:

    #include <stdio.h>
    #include <string.h>
    #include <string>
    #include <iostream>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    const int maxen=100010;
    int T,n,a[maxen],b[maxen],dp[maxen];
    int main(void){
        int t=1;
        scanf("%d",&T);
        while(T--){
            scanf("%d",&n);
            memset(dp,0,sizeof(dp));
            for(int i=1;i<=n;++i){
                scanf("%d",&a[i]);
                b[i]=a[i]-i;
            }
            int len=1;
            dp[1]=b[1];
            for(int i=2;i<=n;++i){
                if(dp[len]<=b[i]){
                    dp[++len]=b[i];
                }
                else{
                    int j=upper_bound(dp+1,dp+1+len,b[i])-dp;   //寻找最长非下降子序列 
                    dp[j]=b[i];
                }
            }
            printf("Case #%d:
    ",t);
            printf("%d
    ",n-len);
            t++;
        }
        return 0;
    

    
    
    今天又学了这两个方法~ヾ(◍°∇°◍)ノ゙ 
    2019.3.5
    --九点了肚子还是好饱的猴


  • 相关阅读:
    Java中两个Long对象如何比较是否相等
    微信小程序data数组push和remove问题
    微信小程序let和var以及const有什么区别
    小程序开发之弹出框
    Windows系统下如何卸载干净mysql
    jQuery序列化表单
    ssm框架使用详解&配置两个数据源
    nginx在一个服务器上配置两个项目,并通过两个不同的域名访问
    nginx跨域设置&文件上传大小限制
    Navicat11连接oracle数据库
  • 原文地址:https://www.cnblogs.com/pipihoudewo/p/10479843.html
Copyright © 2011-2022 走看看