求单调递增最长子序列 动态规划法(DP)

单调递增最长子序列

《求单调递增最长子序列 动态规划法(DP)》

基本思想

动态规划法重要的是确定状态状态转移方程

状态是局部环境下得到的局部解,后项的答案由前面的更小的项决定,前面的更小的项又由更小更小的项决定,直到到达一个边界,这称之为状态转移.如给出一个数组a[11]

如给出一个数组a[11]:

《求单调递增最长子序列 动态规划法(DP)》

状态当前的最长递增子序列,用F[]数组记录,则dp[0]=1;

《求单调递增最长子序列 动态规划法(DP)》

a[1]>a[0],dp[1]=dp[0]+1=2;a[2]>a[3],dp[2]=dp[1]+1=3;直到dp[5]=dp[4]+1=6;

重点:那么dp[6]应该从哪里得来?a[6]=11,找到a[i]<a[6]有i={0,1}而dp[0]=1,dp[1]=2;则dp[6]=max{dp[0],dp[1]}+1=dp[1]+1=3;接下来的变化:

《求单调递增最长子序列 动态规划法(DP)》

从上面的分析中找到规律,即dp[i]的值是前面所有小于a[i]的数组的dp[i]的最大值+1;

*此步骤代码如下:

dp[0]=1;
		for(i=1;i<N;i++){
			int max=-1;
			for(w=0;w<i;w++)if(a[w]<a[i]&&dp[w]>max)max=dp[w];
			dp[i]=max+1;
		}

得到状态转移方程:

《求单调递增最长子序列 动态规划法(DP)》

最后遍历dp[]数组,其最大值即为最长子序列长度;

完整代码:(fond函数为后面的思考答案,与题目无关)

#include<cstring>
#include<cstdio>
const int M=100000;
int a[M],dp[M],L[M];


void found(int max,int N){
	int q,w,i=N-1;
	for(q=max;q>=1;q--){
		for(w=i;w>=0;w--){
			if(dp[w]==q){
				printf("%d ",a[w]);
				break;
			}
			i=w-1;
		}
	}
}


int main(){
	int N;
	while(scanf("%d",&N)!=EOF){
		int i,w;
		for(i=0;i<N;i++)scanf("%d",&a[i]);
		dp[0]=1;
		for(i=1;i<N;i++){
			int max=-1;
			for(w=0;w<i;w++)if(a[w]<a[i]&&dp[w]>max)max=dp[w];
			dp[i]=max+1;
		}
		int max=-1;
		for(i=0;i<N;i++)if(dp[i]>max)max=dp[i];
		printf("%d\n",max);
		found(max,N);
	}
}

思考:

题目只是要求最长的长度,如果要你输出最长的最序列呢?

给出代码:

void found(int max,int N){
	int q,w,i=N-1;
	for(q=max;q>=1;q--){
		for(w=i;w>=0;w--){
			if(dp[w]==q){
				printf("%d ",a[w]);
				break;
			}
			i=w-1;
		}
	}
}

//大一菜鸟一枚,如有错误还望指正

    原文作者:动态规划
    原文地址: https://blog.csdn.net/love_phoebe/article/details/74279763
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞