• 最长上升子序列问题


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

  • 相关阅读:
    django常用命令集合 待完善
    InSAR 数据
    InSAR 处理流程和原理
    InSAR 处理软件
    InSAR 参考书目,文献推荐
    InSAR
    小程序测试方案
    【非原创】测试环境的目的
    【非原创】测试的职责
    api自动生成思路
  • 原文地址:https://www.cnblogs.com/beiyueya/p/12170999.html
Copyright © 2020-2023  润新知