最长单调递减子序列

问题描述:求一个数组的最长递减子序列
比如{9,4,3,2,5,4,3,2}的最长递减子序列为{9,5,4,3,2}。

思路:这是一个标准的动态规划的问题,在不理解算法的时候,最感觉可以使用递归的思想,其实也是正确的,在最后给出一个递归的方法,在知道是动态规划问题以后,就需要进行分析,我们需要一个辅助数组记录信息,假如源数组为src,辅助数组为table,table[i]数组中记录着到src[0]~src[i]这个子数组中包含src[i]构成的最长单调子序列的长度(一定要注意就是table[i]记录了包含src[i]构成的递减序列中最长的那个,也就是以src[i]为结尾的最长递减子序列),如果src[i]大于以前的所有元素,那么table[i]=1.

      
最后的结果就是,table[i] =max{table[k]+1, src[i] > src[k] && 0<k<i},这是初始化了table数组,那么最长递减子序列为max{table[i],0<i<n}.

      
但是需要打印最长子序列,我们已经记录了max{table[i],0<i<n}的下标,那么我们就知道了最长子序列的最后一个元素,同时知道了最长子序列的长度。下面就是递归调用,假如我们已经知道table[k]最大,那么src[k]就是最长递减子序列中的最后一个,如果table[i]+1 = table[k] && src[i] < table[k]时,那么就需要答应src[i]。

#include <stdio.h>
#include <stdlib.h>

void Find(int src[],int n,int table[])
{
	table[0]= 1;
	int i,j,maxi = 0;
	for(i=0;i<n;i++)
	{
		table[i]=1;
		for(j=0;j<i;j++)
		{
/* 这里可能是常有的错误
			if( src[j] > src[i])
			{
				table[i] = table[j] +1;
						if(src[j]>src[i])
							table[i] = table[j]+1;
						if(table[i] > table[maxi])
							maxi = i;
			}
			*/
			   if(src[j]> src[i] && table[j]+1 > table[i])
			   {
			   table[i] = table[j]+1;
			//这个的作用是为了打印存在的,maxi记录最长子序列中最后一个数组元素
			if(table[i] > table[maxi])
			maxi = i;
			}

		}
	}
//	printf("%d\r\n",maxi);
}

void print(int src[],int table[],int maxi)
{
	int i=maxi-1;
	for(;i>=0;i--)
	{
		if(table[maxi] == table[i]+1 && src[i] > src[maxi])
		{
			print(src,table,i);
			break;
		}
	}
	printf("%d ",src[maxi]);
}

void FindLongestDSCArray2(int *arr, int n){
	int mark[9];
	int link[9];

	int i = 0;
	for(i=0;i<n;i++){
		mark[i] = 0;
		link[i] = -1;
	}
	//link[0] = 1;

	int j = 0, maxMark = 0;
	for(i=0;i<n;i++){
		maxMark = 0;
		for(j=0;j<i;j++){
			if(arr[j]>arr[i]){
				if(maxMark<mark[j]){
					maxMark = mark[j];
					link[i] = j;
				}

			}
		}
		mark[i] = maxMark+1;
	}
	for(i=0;i<9;i++)
		printf("%d ",mark[i]);
	printf("\r\n");
	for(i=0;i<9;i++)
		printf("%d ",link[i]);
	printf("\r\n");

/*
	//Print()
	int node = 0;
	maxMark = 0;
	for(i=0;i<n;i++){
		if(mark[i]>maxMark)
			node = i;
	}

	while(node != -1){
		printf("%d ",arr[node]);
		node = link[node];
	}
	*/
}

int main()
{
	int src[]={9,4,3,2,5,4,3,2,4};
	int table[9];
	Find(src,9,table);

    FindLongestDSCArray2(src,9);
	int i=0;
	for(;i<9;i++)
		printf("%d ",table[i]);
	printf("\r\n");
	return 0;
}

时间: 2024-12-29 01:49:03

最长单调递减子序列的相关文章

POJ 1552 BUY LOW, BUY LOWER(最长单调递减子序列求方案数)

BUY LOW, BUY LOWER Time Limit: 1000MS   Memory Limit: 30000K       Description The advice to "buy low" is half the formula to success in the bovine stock market.To be considered a great investor you must also follow this problems' advice: "

动态规划(4)———最长上升子序列(拦截导弹NYOJ79)

拦截导弹 描述 某国为了防御敌国的导弹袭击,发展中一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于等于前一发的高度.某天,雷达捕捉到敌国导弹来袭.由于该系统还在试用阶段,所以只用一套系统,因此有可能不能拦截所有的导弹. 输入 第一行输入测试数据组数N(1<=N<=10)接下来一行输入这组测试数据共有多少个导弹m(1<=m<=20)接下来行输入导弹依次飞来的高度,所有高度值均是大于0的正整数. 输出 输出最多能拦截的

poj 1952 BUY LOW, BUY LOWER[最长单调子序列变形]

题目:poj 1952 BUY LOW, BUY LOWER 题意:给出一个序列,先求最长单调递减子序列,然后求在子序列最长的情况下,不同的长度都为最长的的子序列的个数.(比如3,2,1和3,2,1属于相同,只能算一个) 分析:首先用一个dp[i]表示到当前i点的最长子序列的长度 用dp2[i]表示最长为dp[i]的子序列的个数 然后dp[i] = max(dp[j])+1 (1<=j /************************************ Problem: 1952 Use

14-高效求最长公共子序列(二维数组存不下)

/*                                   See LCS again时间限制:1000 ms  |  内存限制:65535 KB难度:3 描述 There are A, B two sequences, the number of elements in the sequence is n.m; Each element in the sequence are different and less than 100000. Calculate the length

POJ 2533 - Longest Ordered Subsequence(最长上升子序列) 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:http://poj.org/problem?id=2533 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)

最长公共子序列的代码实现

关于最长公共子序列(LCS)的相关知识,http://blog.csdn.net/liufeng_king/article/details/8500084 这篇文章讲的比较好,在此暂时不再详说. 以下是我代码实现两种方式:递归+递推: 1 #include <bits/stdc++.h> 2 using namespace std; 3 int A[100]; 4 int B[100]; 5 6 //int B[]={2,3,5,6,9,8,4}; 7 int d[100][100]={0};

HDU 3998 Sequence (最长递增子序列+最大流SAP,拆点法)经典

Sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1666    Accepted Submission(s): 614 Problem Description There is a sequence X (i.e. x[1], x[2], ..., x[n]). We define increasing subsequ

算法面试题 之 最长递增子序列 LIS

找出最长递增序列 O(NlogN)(不一定连续!) 参考 http://www.felix021.com/blog/read.php?1587%E5%8F%AF%E6%98%AF%E8%BF%9E%E6%95%B0%E7%BB%84%E9%83%BD%E6%B2%A1%E7%BB%99%E5%87%BA%E6%9D%A5 我就是理解了一下他的分析 用更通俗易懂的话来说说题目是这样 d[1..9] = 2 1 5 3 6 4 8 9 7 要求找到最长的递增子序列首先用一个数组b[] 依次的将d里面

NYOJ 36 &amp;&amp;HDU 1159 最长公共子序列(经典)

链接:click here 题意:tip:最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(Longest Common Subsequence).其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列. 输入 第一行给出一个整数N(0<N<100)表示待测数据组数 接下来每组数据两行,分别为待测的两组字符串.每个字符串长度不大于1000. 输出 每组测试数据输出一个整数,表示最长公共子序列长度.每组