zoukankan      html  css  js  c++  java
  • 动态规划题目一:最长单调递增子序列

    习题3-1:最长单调递增子序列

    [算法设计与实验题解 page 63]

    问题描述:
    所谓子序列,就是在原序列里删掉若干个元素后剩下的序列,以字符串"abcdefg"为例子,去掉bde得到子序列"acfg"
    现在的问题是,给你一个数字序列,你要求出它最长的单调递增子序列。

    输入:
    多组测试数据,每组测试数据第一行是n(1<=n<=10000),下一行是n个比1e9小的非负整数

    输出:
    对于每组测试数据输出一行,每行内容是最长的单调递增子序列的长度

    样例输入:
    5
    1 2 4 8 16
    5
    1 10 4 9 7
    9
    0 0 0 1 1 1 5 5 5

    样例输出:
    5
    3
    3

    我的Java 代码一:

    /**
    * 算法时间复杂度是O(n^2)
    * 用数组b[0:n-1]记录以a[i],0<=i<n为结尾的元素的最长的递增子序列长度
    * 序列a的最长的递增子序列的长度是max{b[i]}(0<=i<n),b[i]满足最优子结构,可以递归的定义:
    * b[0]=1;b[i]=max{b[k]}+1 (0<=k<i,a[k]<a[i])
    */
    import java.util.Scanner;

    public class LIS {

    public static int l;
    public static int maxl;
    public static int[] a;
    public static int[] b;
    public static void main(String[] args) {
    Scanner sin
    =new Scanner(System.in);
    while(sin.hasNext()){
    l
    =sin.nextInt();
    a
    =new int[l];
    b
    =new int[l];//记住数组一定要初始化给定一个大小,不然后面赋值时会报空指针错误
    for(int i=0;i<l;i++){
    a[i]
    =sin.nextInt();
    }
    maxl
    =dp();
    System.out.println(maxl);
    }
    }
    private static int dp() {
    int i,j,k,t;
    t
    =0;
    b[
    0]=1;
    for(i=0;i<l;i++){
    k
    =0;
    for(j=0;j<i;j++){
    if(a[i]>a[j] && k<b[j]){
    k
    =b[j];
    }
    }
    b[i]
    =k+1;
    }
    for(i=0;i<l;i++){
    if(t<b[i]){
    t
    =b[i];
    }
    }
    return t;
    }
    }


    我的Java 代码二:

    /**
    * 算法时间复杂度是O(nlog(n))
    * 通过归纳假设得到问题变为:已知计算序列a的最长的递增子序列的长度k以及序列
    * a中所有长度为k的递增子序列中的最小结尾元素b[k]
    */
    import java.util.Scanner;

    public class LIS2 {

    public static int l;
    public static int maxl;
    public static int[] a;
    public static int[] b;
    public static void main(String[] args) {
    Scanner sin
    =new Scanner(System.in);
    while(sin.hasNext()){
    l
    =sin.nextInt();
    a
    =new int[l];
    b
    =new int[l+1];
    for(int i=0;i<l;i++){
    a[i]
    =sin.nextInt();
    }
    dp();
    System.out.println(maxl);
    }
    }
    private static void dp() {
    int i,low,up,mid;
    b[
    1]=a[0];
    maxl
    =1;
    for(i=1;i<l;i++){
    if(a[i]>b[maxl]){//此时最大长度要加1,并且要改变最小元素值
    maxl++;
    b[maxl]
    =a[i];
    }
    else if(a[i]<b[1]){//如果比第一个元素还要小,那么就换一下最小的元素值
    b[1]=a[i];
    }
    else{//这种情况下要找到合适的位置将a[i]插入到b中的某个位置

    low
    =1;
    up
    =maxl;

    // while(low!=up-1){//原书的写法
    // mid=(low+up)/2;
    // //System.out.println(low+" "+up+" "+mid);
    // //System.out.println(b[mid]+" "+a[i]);
    // if(b[mid]<=a[i]){//找到满足b[j-1]<=a[i]<b[j]的j(=up)
    // low=mid;
    // }else{
    // up=mid;
    // }
    // //System.out.println(low+" "+up+" "+mid);
    // }
    // b[up]=a[i];

    while(low<up){//另一种写法,更加符合二分查找
    mid=(low+up)/2;//注意条件:low等于up时就要退出了
    //System.out.println(low+" "+up+" "+mid);
    //System.out.println(b[mid]+" "+a[i]);
    if(b[mid]<=a[i]){//找到满足b[j-1]<=a[i]<b[j]的j(=up)
    low=mid+1;
    }
    else{
    up
    =mid-1;
    }
    //System.out.println(low+" "+up+" "+mid);
    }
    b[up]
    =a[i];
    }
    }
    }
    }

    其他的资源:

    可供参考的资料:

    1.这道题目的两种解题算法总结博客:http://old.blog.edu.cn/user2/43845/archives/2006/1115309.shtml

    2.国家集训队论文 李睿的论文:〈二分法和统计研究〉:http://wenku.baidu.com/view/313fbcd126fff705cc170a18.html

    3.论坛中的其他解题方法:http://yzfy.org/dis/listpost.php?tid=101

  • 相关阅读:
    【洛谷P1330】封锁阳光大学
    【洛谷P1087】FBI树
    hdu 4504(动态规划)
    hdu 4503(数学,概率)
    hdu 5400(思路题)
    hdu 5701(区间查询思路题)
    hdu 4502(DP)
    hdu 1401(单广各种卡的搜索题||双广秒速)
    hdu 1258(DFS)
    hdu 1254(搜索题)
  • 原文地址:https://www.cnblogs.com/yinger/p/2111269.html
Copyright © 2011-2022 走看看