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;//最長子序列的個數
}

 

 

 

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