博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
AC解 - Longest Ordered Subsequence(最长递增子序列)
阅读量:5070 次
发布时间:2019-06-12

本文共 4741 字,大约阅读时间需要 15 分钟。

原题:

1) ZOJ:   http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2136

2) POJ: http://poj.org/problem?id=2533

问题描述:

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, the 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 of this sequence 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.

分析:分两种情况:

第一种情况:考虑输入序列的右边部分m个 元素, 用f(ai,m)表示最长可能递增子序列中右边部分为(ai, a_i1, a_i2, ..., a_ik)得到的长度,其中(a_i1, a_i2, ..., a_ik)表示输入序列右边部分m个 元素构成的最长递增子序列,该序列前面一个元素即为ai。ai可以为输入序列左边部分共N-m个元素中的任何一个。

假设输入序列的右边部分m个 元素的排列顺序为:a_j1, a_j2, ..., a_jm,那么 f(ai,m)关联的最长递增子序列中可能包含第一个元素a_j1,也可能不包含它。

a) 如果包含 a_j1,那么f(ai,m)可以表示成:

             0或者1 + f(a_j1,m-1)         

其中 a_j1 > ai时,二者构成递增关系,这时取值 1 + f(a_j1,m-1);如果 a_j1 <= ai时,二者不构成递增关系,这时取值0。

b) 如果不包含 a_j1,那么f(ai,m)可以表示成:  

             f(ai,m-1)           

要使 f(ai,m)符合最优解,显然得到递推关系

             f(ai,m) = max( 1 + f(a_j1,m-1),  f(ai,m-1) )      .....式1

这里 1 + f(a_j1,m-1)部分 要求 a_j1 > ai。

第二种情况:如果 最长递增子序列中前面N-m个元素都未出现,同样考虑: 用g(m)表示最长可能递增子序列中右边部分为(a_i1, a_i2, ..., a_ik)得到的长度。假设输入序列的右边部分m个 元素的排列顺序为:a_j1, a_j2, ..., a_jm,那么g( m)关联的最长递增子序列中可能包含第一个元素a_j1,也可能不包含它。

a) 如果包含 a_j1,那么g(m)可以表示成: f( a_j1,m-1)

b) 如果不包含 a_j1,那么g(m)可以表示成:g(m-1)

同样取二者的最大值得到:            

             g(m) = max( f( a_j1,m-1), g(m-1) )                   .....式2

初始值g(0)=0,因为 输入序列 右 边没有任何元素时最大长度为0;

以上两种情况中 初始值 f(ai,0)=1,ai为输入序列中任何一个元素,因为该元素本身构成最长 递增子序列。  

例如输入序列为(1,7,3,5,9,4,8),那么当m=2时,右边的序列为(4,8),前面共有5个元素(1,7,3,5,9),所以可得到6个递推关系式:

  f(1,2) = max( 1 + f(4,1),  f(1,1) )  因为1<4

  f(7,2) = max( 0,  f(7,1) )  因为7>=4

  f(3,2) = max( 1 + f(4,1),  f(3,1) )  因为3<4

  f(5,2) = max( 0,  f(5,1) )  因为5>=4

  f(9,2) = max( 0,  f(9,1) )  因为9>=4

  g(2) = max(f(4,1), g(1))

每次需要计算的值的个数为N-m+1 (m=1,2,..., N),具体实现时只需存储相邻两轮循环的值,即前一轮循环得到 N-m个值,本轮循环得到 N-m+1个值。在以下的实现中,用数组F[]表示 前一轮循环得到的值,用 数组 currF[] 表示 本 轮循环得到的值, g(m)的值作为数组的最后一个元素存放。时间复杂度为O(n^2),空间复杂度为O(n)。

解法(针对ZOJ)

import java.util.Scanner;public class Main {	public static int solve(int A[]) {		int N = A.length;		int[] F = new int[N + 1];		for (int i = 0; i < N; i++) {			F[i] = 1;		}		F[N] = 0;		for (int rightCount = 1; rightCount <= N; rightCount++) {			int head = A[N - rightCount];			int leftCount = N - rightCount;			int[] currF = new int[N + 1 - rightCount];			int headPrevVal = F[N - rightCount];			for (int i = 0; i < leftCount; i++) {				int includeHeadCase = 0;				if (A[i] < head) {					includeHeadCase = 1 + headPrevVal;				}				int excludeHeadCase = F[i];				int optimalVal = (includeHeadCase < excludeHeadCase) ? excludeHeadCase						: includeHeadCase;				currF[i] = optimalVal;			}			int prevSpecialVal = F[F.length - 1];			int specialOptimal = headPrevVal < prevSpecialVal ? prevSpecialVal					: headPrevVal;			currF[currF.length - 1] = specialOptimal;			F = currF;		}		return F[F.length - 1];	}	public static void main_test(String[] args) {		int[] A = { 1, 7, 3, 5, 9, 4, 8 };		int result = Main.solve(A);		System.out.println(result);	}	public static void main(String[] args) {		Scanner cin = new Scanner(System.in);		String line = cin.nextLine();		line = line.trim();		int testCasesNum = Integer.parseInt(line);		int[][] testCases = new int[testCasesNum][];		// blank line		cin.nextLine();		for (int i = 0; i < testCasesNum; i++) {			line = cin.nextLine();			line = line.trim();			int size = Integer.parseInt(line);			// read the sequence			line = cin.nextLine();			line = line.trim();			int[] seq = new int[size];			String[] tokens = line.split(" ");			for (int j = 0; j < tokens.length; j++) {				String token = tokens[j].trim();				if (token.length() > 0 && j < size) {					seq[j] = Integer.parseInt(token);				}			}			testCases[i] = seq;			// blank line			if (i < testCasesNum - 1)				cin.nextLine();		}		for (int i = 0; i < testCasesNum; i++) {			int[] seq = testCases[i];			int result = Main.solve(seq);			System.out.println(result);			if (i < testCasesNum - 1) {				System.out.println();			}		}	}}

解法(针对POJ): 和针对ZOJ的解法一样,只是输入和输出不太一样(ZOJ可以输入多个test cases,POJ只输入一个test case)。下面是main(...)方法的写法:

public static void main(String[] args) {		Scanner cin = new Scanner(System.in);		String line = cin.nextLine();		line = line.trim();		int size = Integer.parseInt(line);		// read the sequence		line = cin.nextLine();		line = line.trim();		int[] seq = new int[size];		String[] tokens = line.split(" ");		for (int j = 0; j < tokens.length; j++) {			String token = tokens[j].trim();			if (token.length() > 0 && j < size) {				seq[j] = Integer.parseInt(token);			}		}		int result = Main.solve(seq);		System.out.println(result);	}

转载于:https://www.cnblogs.com/ljsspace/archive/2011/06/11/2078539.html

你可能感兴趣的文章
AngularJS学习篇(一)
查看>>
关于Xshell无法连接centos6.4的问题
查看>>
css3动画——基本准则
查看>>
输入月份和日期,得出是今年第几天
查看>>
pig自定义UDF
查看>>
spring security 11种过滤器介绍
查看>>
代码实现导航栏分割线
查看>>
大数据学习系列(8)-- WordCount+Block+Split+Shuffle+Map+Reduce技术详解
查看>>
【AS3代码】播放FLV视频流的三步骤!
查看>>
枚举的使用
查看>>
luogu4849 寻找宝藏 (cdq分治+dp)
查看>>
日志框架--(一)基础篇
查看>>
关于源程序到可运行程序的过程
查看>>
转载:mysql数据库密码忘记找回方法
查看>>
scratch少儿编程第一季——06、人在江湖混,没有背景怎么行。
查看>>
C# Async与Await的使用
查看>>
Mysql性能调优
查看>>
iOS基础-UIKit框架-多控制器管理-实例:qq界面框架
查看>>
自定义tabbar(纯代码)
查看>>
小程序底部导航栏
查看>>