最长上升子序列问题

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就当改了哦

posted @ 2020-01-09 13:35  北月真好  阅读(135)  评论(0编辑  收藏  举报