最长递增子序列(POJ2533)

题目

Description

A numeric sequence of ai is ordered if a1 < a2 < … < aN. Let the subsequence of the given numeric sequence (a1, a2, …, aN) be any sequence (ai1, ai2, …, aiK), where 1 <= i1 < i2 < … < iK <= N. For example, sequence (1, 7, 3, 5, 9, 4, 8) has ordered subsequences, e. g., (1, 7), (3, 4, 8) and many others. All longest ordered subsequences are of length 4, e. g., (1, 3, 5, 8).

Your program, when given the numeric sequence, must find the length of its longest ordered subsequence.
Input

The first line of input file contains the length of sequence N. The second line contains the elements of sequence - N integers in the range from 0 to 10000 each, separated by spaces. 1 <= N <= 1000
Output

Output file must contain a single integer - the length of the longest ordered subsequence of the given sequence.
Sample Input

7
1 7 3 5 9 4 8
Sample Output

4

题目大意

  什么是最长递增子序列呢?例如有一组数3 7 1 2 5,它的递增子序列有3 7 1 2 5 37 35 12 15 125。那么它的最长递增子序列的长度为3。即|125|=3;我们不要求这些子序列中的每个元素是相邻在一起的,只要保证他们递增即可。

思路

  这道题和最大连续子序列和的思想一样。都是先固定一个元素,然后求以这个元素为末尾元素的最大递增子序列。比如上例的3 7 1 2 5,如果我们固定3为末尾 元素,那么最大递增子序列只能为3;如果7为末尾元素,那么它的最大递增子序列为37;如果1为末尾元素,那么最大递增子序列只能为1,因为它前面的3和7都比它大…以此类推。
  那么我们就可以定义F(n)为以An为末尾元素的最长递增子序列的长度。那么由上面的分析我们知道,F(n)有两种情况。

  1. An前面的元素都比它大,或者An就是第一个元素,那么F(n)就等于1,也就是以An为末尾元素的最大递增子序列只有它本身。
  2. An前面存在比它大的元素,以An为末尾元素的最大递增子序列就等于An前面的最大递增子序列加上An,所以F(n) = Max|…Ai| + |Aj|,其中i<j&Ai<Aj

  综上,F(n) = 1 或者 F(n) = F(i) + 1,其中Ai <An且i<n
  有了这个公式,我们就可以写代码了。代码有三种写法:

  1. 朴素的递归算法
  2. 自顶而下的备忘录法
  3. 自底向上的递归算法

朴素的递归算法

#include <iostream>
#include <cmath>
#include <algorithm>

using namespace std;

const int MAXN = 1010;

int arr[MAXN];

int Func1(int n){
    int answer;
    if( n == 0){
        answer = 1;
    }
    else{
        answer = 1;
        for(int i=0;i<n;i++){
            if(arr[i] < arr[n]){
                answer = max(answer,Func1(i)+1);
            }
        }
    }
    return answer;
}

int main()
{
    int N;
    scanf("%d",&N);
    for(int i=0;i<N;i++){
        scanf("%d",&arr[i]);
    }
    int maxNum = 0;
    for(int i=0;i<N;i++){
        maxNum = max(maxNum,Func1(i));
    }
    printf("%d\n",maxNum);
    return 0;
}

自顶向下的备忘录法(递归+记忆化)

#include <iostream>
#include <cmath>
#include <algorithm>

using namespace std;

const int MAXN = 1010;

int arr[MAXN];

int Func1(int n){
    int answer;
    if( n == 0){
        answer = 1;
    }
    else{
        answer = 1;
        for(int i=0;i<n;i++){
            if(arr[i] < arr[n]){
                answer = max(answer,Func1(i)+1);
            }
        }
    }
    return answer;
}

int memo[MAXN];
int Func2(int n){
    int answer;
    if(memo[n] != -1){
        answer = memo[n];
    }else{
        if( n == 0){
            answer = 1;
        }
        else{
            answer = 1;
            for(int i=0;i<n;i++){
                if(arr[i] < arr[n]){
                    answer = max(answer,Func2(i)+1);
                }
            }
        }
        memo[n] = answer;
    }
    return answer;
}

int main()
{
    int N;
    scanf("%d",&N);
    for(int i=0;i<N;i++){
        scanf("%d",&arr[i]);
    }
//    int maxNum = 0;
//    for(int i=0;i<N;i++){
//        maxNum = max(maxNum,Func1(i));
//    }
//    printf("%d\n",maxNum);
    fill(memo,memo+N,-1);  //初始化
    int maxNum = 0;
    for(int i=0;i<N;i++){
        maxNum = max(maxNum,Func2(i));
    }
    printf("%d\n",maxNum);
    return 0;
}

自底向上的递推算法

#include <iostream>
#include <cmath>
#include <algorithm>

using namespace std;

const int MAXN = 1010;

int arr[MAXN];

int Func1(int n){
    int answer;
    if( n == 0){
        answer = 1;
    }
    else{
        answer = 1;
        for(int i=0;i<n;i++){
            if(arr[i] < arr[n]){
                answer = max(answer,Func1(i)+1);
            }
        }
    }
    return answer;
}

int memo[MAXN];
int Func2(int n){
    int answer;
    if(memo[n] != -1){
        answer = memo[n];
    }else{
        if( n == 0){
            answer = 1;
        }
        else{
            answer = 1;
            for(int i=0;i<n;i++){
                if(arr[i] < arr[n]){
                    answer = max(answer,Func2(i)+1);
                }
            }
        }
        memo[n] = answer;
    }
    return answer;
}

//用递推的方法算出每一个F(n)
int dp[MAXN];
void Func3(int n){
    int answer;
    for(int i=0;i<n;i++){
        if(i == 0){
            answer = 1;
        }else{
            answer = 1;
            for(int j=0;j<i;j++){
                if(arr[j] < arr[i]){
                    answer = max(answer,dp[j]+1);
                }
            }
        }
        dp[i] = answer;
    }
    return;
}

int main()
{
    int N;
    scanf("%d",&N);
    for(int i=0;i<N;i++){
        scanf("%d",&arr[i]);
    }
//    int maxNum = 0;
//    for(int i=0;i<N;i++){
//        maxNum = max(maxNum,Func1(i));
//    }
//    printf("%d\n",maxNum);
//    fill(memo,memo+N,-1);  //初始化
//    int maxNum = 0;
//    for(int i=0;i<N;i++){
//        maxNum = max(maxNum,Func2(i));
//    }
//    printf("%d\n",maxNum);
    fill(dp,dp+N,-1);  //初始化
    int maxNum = 0;
    Func3(N);
    for(int i=0;i<N;i++){
        maxNum = max(maxNum,dp[i]);
    }
    printf("%d\n",maxNum);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是Java解决POJ3233—矩阵幂序列问题的代码和解释: ```java import java.util.Scanner; public class Main { static int n, k, m; static int[][] A, E; public static void main(String[] args) { Scanner sc = new Scanner(System.in); n = sc.nextInt(); k = sc.nextInt(); m = sc.nextInt(); A = new int[n][n]; E = new int[n][n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { A[i][j] = sc.nextInt() % m; E[i][j] = (i == j) ? 1 : 0; } } int[][] res = matrixPow(A, k); int[][] ans = matrixAdd(res, E); printMatrix(ans); } // 矩阵乘法 public static int[][] matrixMul(int[][] a, int[][] b) { int[][] c = new int[n][n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { for (int k = 0; k < n; k++) { c[i][j] = (c[i][j] + a[i][k] * b[k][j]) % m; } } } return c; } // 矩阵快速幂 public static int[][] matrixPow(int[][] a, int b) { int[][] res = E; while (b > 0) { if ((b & 1) == 1) { res = matrixMul(res, a); } a = matrixMul(a, a); b >>= 1; } return res; } // 矩阵加法 public static int[][] matrixAdd(int[][] a, int[][] b) { int[][] c = new int[n][n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { c[i][j] = (a[i][j] + b[i][j]) % m; } } return c; } // 输出矩阵 public static void printMatrix(int[][] a) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { System.out.print(a[i][j] + " "); } System.out.println(); } } } ``` 解释: 1. 首先读入输入的n、k、m和矩阵A,同时初始化单位矩阵E。 2. 然后调用matrixPow函数求出A的k次幂矩阵res。 3. 最后将res和E相加得到结果ans,并输出。 4. matrixMul函数实现矩阵乘法,matrixPow函数实现矩阵快速幂,matrixAdd函数实现矩阵加法,printMatrix函数实现输出矩阵。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值