DP之最长上升子序列

前言:我们先了解一下最长连续递增子序列的求解

#include<bits/stdc++.h>
using namespace std;
//求最长连续递增序列 
#define maxn 100000
int n,a[maxn],dp[maxn];//dp[i]即前i个元素的上升子序列的长度 
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		dp[i]=1;//初始值设为1
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		if(a[i]>a[i-1])	dp[i]=dp[i-1]+1;
		ans=max(ans,dp[i]);
	}
	cout<<ans<<endl;
}
 

最长上升子序列:求解的这个和上面的求解点不同,我们这个的子序列是可以非连续的。

题目:求最长上升子序列
题目描述:给出一个数列{a1,a2,...,an},要求你选出尽量多的元素,使这些元素按其相对位置单调递增。
任务就是对于给定的序列,求出最长上升子序列的长度。
输入数据:输入的第一行是序列的长度N(1<=N<=1000)。第二行给出序列中的N个整数,这些整数的取值范围都是0~10000。
输出要求:最长上升子序列的长度。
输入样例:
7
1   7    3    5    9     4    8
输出样例:
4

解决方案:DP算法(o(n^2))

dp[i]表示前i个元素的最长上升子序列的长度

决策:第i个元素加到前面哪一个序列k末尾,会使上升子序列的长度最大?

那必然是dp[k]的值越大,dp[i]就越大。

dp[i]=dp[k]+1;其中:1<=k<=i-1   找到dp值最大的k

#include<bits/stdc++.h>
using namespace std;
//求最长递增子序列 
#define maxn 100000
int n,a[maxn],dp[maxn];//dp[i]即前i个元素的上升子序列的长度 
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		dp[i]=1;//初始值设为1
	}
	int ans=0;
	for(int i=1;i<=n;i++){//决策:dp[i]=dp[k]+1   找到一个最好的k 
		for(int j=1;j<i;j++){//找到j始得dp[i]最大 
			if(a[i]>a[j])
			dp[i]=max(dp[i],dp[j]+1);
		} 
		ans=max(ans,dp[i]);
	}
	cout<<ans<<endl;
}
 

求:(最长上升子序列)的个数

讨论:我们这里比前面的更复杂了一点,需要求有多少个最长上升子序列的个数。

#include<bits/stdc++.h>
using namespace std;
//求最长递增子序列 
#define maxn 100000
int dp[maxn],a[maxn],ct[maxn],n;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		dp[i]=1;//初始化为1 
		ct[i]=1;
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<i;j++){
			if(a[i]>a[j]){//说明为上升子序列 
				//dp[i]=max(dp[i],dp[j]+1)
				if(dp[i]==(dp[j]+1)){
					ct[i]+=ct[j];
				} 
				else if(dp[i]<(dp[j]+1)){
					dp[i]=(dp[j]+1);
					ct[i]=ct[j];
				}
			}
		}
		ans=max(ans,dp[i]);
	}
	cout<<ans<<endl;
	int res=0;
	for(int i=1;i<=n;i++){
		if(ans==dp[i]){
			res+=ct[i];
		}
	}
	cout<<res<<endl;//最长子序列的个数
}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章