最长上升子序列问题
1,坚持与否,成功与否,真还挺难说的。
2,有一个长为n的数列a0,a1,....an-1。请求出这个序列中最长的上升子序列的长度,上升子序列指的是对于任意i<j都满足ai<aj的子序列。
3,嗯还行我不会。奇奇怪怪用DP。LIS问题。。之前是不是还有另一个啥。。。
4,
#include<iostream> using namespace std; int n, a[1005]; int dp[1005]; int main(){ cin>>n; for(int i=0;i<n;i++) cin>>a[i]; int res=0; for(int i=0;i<n;i++){ dp[i]=1; for(int j=0;j<i;j++){ if(a[j]<a[i]){ dp[i]=max(dp[i],dp[j]+1); } res=max(res,dp[i]); } } cout<<res<<endl; }
5,奇奇怪怪,res咋能递增呢。(res递增你是没看懂人家dp的定义啊)
额自动保存个屁啊。没有,,
6,开始费大和费小。
人家先是定义dp[i[为以ai为末尾的最长上升子序列的长度。
不久之前那个开门见山么。那直接背算了。这样死记硬背感觉不太好。确实不太好,但是也没啥太好的方法。
dp就背定义和递推式呗。。
dp[i]=max{1,dp[j]+1|j<i且aj<ai};
那么费大就到此为止。
我们来费小。
倒是推了一遍明白了不少道理。但是到底是个什么东西呢?
有点像堆积木??递推??
堆积木吧?倒不如说是附加。
7,就算改了
#include<iostream> using namespace std; int n,a[1005],dp[1005]; int main(){ cin>>n; for(int i=0;i<n;i++) cin>>a[i]; int res=0; for(int i=0;i+1<n+1;i++){ dp[i]=1; for(int j=0;j<i;j++){ if(a[j]<a[i]) { dp[i]=max(dp[i],dp[j]+1); } res=max(res,dp[i]); } } cout<<res<<endl; }
呵呵呵俄呵呵呵。
8,第二种DP。
还用一个fill函数的应用。在#include<algorithm>中,
先来介绍下lower_bound函数。书上解释的怪那啥的。
#include <algorithm> #include <iostream> using namespace std; int main() { int a[]={1,2,3,4,5,7,8,9}; printf("%d",lower_bound(a,a+8,6)-a); return 0; } 输出:5
就是返回大于等于key值得第一个位置。
顺便..
函数upper_bound() 功能:函数upper_bound()返回的在前闭后开区间查找的关键字的上界,返回大于val的第一个元素位置
虽然有点玄幻但是还是挺容易懂得。
#include<iostream> #include<algorithm> using namespace std; const int INF=1005; int n,dp[1005],a[1005]; int main(){ cin>>n; for(int i=0;i<n;i++) cin>>a[i]; fill(dp,dp+n,INF); for(int i=0;i<n;i++) { *lower_bound(dp,dp+n,a[i])=a[i]; } int ans=lower_bound(dp,dp+n,INF)-dp; cout<<ans<<endl; }
让我们来费大费小,这费大挺难费得,说实话,
来,我们打一遍,前面我们利用DP求取针对最末位得元素得最长得子序列。如果子序列的长度相同,那么最末尾的元素较小的在之后回会更加有优势,所以我们再反过来用DP针对相同长度情况下最小的末尾元素进行求解。
dp[i]:=长度为i+1的上升子序列中末尾元素的最小值,(不存在的话就是INF),联系一下情况好像是这样。
让我们来看看如何用DP来更新这个数组。
最开始全部dp[i]的值都初始化为INF。然后由前到后逐个考虑数组的元素,
对于每个aj,如果i=0或者dp[i-1]<aj的话,就用dp[i]=min(dp[i],aj)进行更新。
这种抽象的东西你得把它弄清,然而你该如何把这个东西给弄清。
模拟呗,我先把代码细节模拟一下,再去带文字上的东西,
lower_bound就隐含着一个要比较的过程。
我觉得现在就看你能用什么手段把这个东西给弄一弄。。除了模拟???
所以这里放个坑算了,关于文字的推导不对。。你看看想个方法吧。
我很惭愧,改不出来啥。
#include<iostream> #include<algorithm> using namespace std; const int INF=1005; int n,dp[1005],a[1005]; int main(){ cin>>n; for(int i=0;i<n;i++) cin>>a[i]; fill(dp,dp+n+1,INF); for(int i=0;i<n;i++) { *lower_bound(dp,dp+n+1,a[i])=a[i]; } int ans=lower_bound(dp,dp+n+1,INF)-dp; cout<<ans<<endl; }
加个1就当改了哦