经典DP问题系列之二:求解最长递增子序列问题

【问题描述:】给定一个长度为N的数组,找出一个最长的单调自增子序列(不一定连续,但是顺序不能乱)
例如:给定一个长度为8的数组A{1,3,5,2,4,6,7,8},则其最长的单调递增子序列为{1,2,4,6,7,8},长度为6.

【求解思路】
本题也是一道经典的dp问题,最近一直在刷hdu的动态规划习题,发现很多动规题都是从这几个经典习题上面延伸过来的:1.数字三角形。2.最大连续子序列和问题。3.最长递增子序列问题。4.背包问题。而今天又遇到了一道类似第3种的dp题,我就干脆把最长递增子序列问题给总结一遍。

其实这一题的思路应该来说和最大连续子序列和很像,我们可以将dp[i]设为以a[i]结尾的最长递增子序列的长度值!状态转移和子序列和问题也是很像的,dp[i] = max(dp[k]) + 1(其中:a[k] < a[i])

最后遍历一遍数组返回最大的dp值就是我们所需的结果!总体来说和子序列和问题的分析思路完全一样

参考代码:

/*
9
2 1 5 3 6 4 8 9 7

结果:1 , 3 , 4, 8, 9   
等于5 
*/
#include
using namespace std;

const int maxn = 100;
int a[maxn];
int dp[maxn];

int Dp(int n)			//dp[i]定义为以a[i]结尾的最长递增子序列长度 
{
	dp[1] = 1;
	for(int i = 2;i <= n;i++)
	{
		int max_r = 0;
		for(int k = 1;k < i;k++)
		{
			if(a[i] > a[k] && dp[k] > max_r)
				max_r = dp[k];
		}
		dp[i] = max_r + 1;
	} 
	//打印dp数组 
	/*for(int i = 1;i <= n;i++)
	{
		cout << dp[i] << " ";
	}*/
	//找出最大的
	int max_res = 0; 
	for(int i = 1;i <= n;i++)
	{
		if(dp[i] > max_res)
			max_res = dp[i];
	}
	return max_res;
}

int main()
{
	int n;
	while(scanf("%d", &n) != EOF)
	{
		for(int i = 1;i <= n;i++)
		{
			cin >> a[i];
		}
		cout << Dp(n) << endl;
	}
	return 0;
}

你可能感兴趣的:(DP,数据结构与算法)