最长上升序列

17401788-c51e4b00e12227bb.png

每一个数之前的上升序列个数
dp[i]:以ai为末尾的最长上升子序列的长度
以ai结尾的上升子序列是:
只包含ai的子序列
在满足j<i且aj<ai的以aj为结尾的上升子序列末尾,追加上ai后得到的子序列(时间为O(n^2))

#include <bits/stdc++.h>
using namespace std;
int dp[1001];
int n,a[1001];
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);//因为本身就是1个了 
        res=max(res,dp[i]);
    }   
    printf("%d\n",res);
    return 0;
}

用DP针对相同长度情况下最小末尾元素进行求解
最开始全部dp的值初始化为INF。然后由前到后逐个考虑数列的元素,对于每个aj,如果i=0或者dp[i-1]<aj的话,就用dp[i]=min(dp[i],aj)进行更新,最终找到是的dp[i]<INF的最大的i+1就是结果了。利用二分搜索(时间O(nlogn))

#include <bits/stdc++.h>
using namespace std;
int dp[1001];
int n,a[1001];
int INF=1000000;
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];
    printf("%d\n",lower_bound(dp,dp+n,INF)-dp);
    return 0;
}
17401788-d309b5b018db5e57.png
过程

知识点补充

  • lower_bound( )和upper_bound( )都是利用二分查找的方法在一个排好序的数组中进行查找的。
  • 在从小到大的排序数组中,
  • lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
  • upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
  • 在从大到小的排序数组中,重载lower_bound()和upper_bound()
  • lower_bound( begin,end,num,greater<type>() ):从数组的begin位置到end-1位置二分查找第一个小于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
  • upper_bound( begin,end,num,greater<type>() ):从数组的begin位置到end-1位置二分查找第一个小于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

FatMouse's Speed

//#include <bits/stdc++.h>
using namespace std;
int dp[1001],rem[1001];
int a[1001];
int INF=1000000;
typedef struct Mouse{
    int weight;//重量
    int speed;//速度
    int num;//编号 
}mice;
mice s[10001];
bool cmp(mice x,mice y){
    if(x.weight==y.weight)
        return x.speed<y.speed;
    else
        return x.weight>y.weight;
}

int main(){
    int n,m,maxn,i,j,k,t,mark;
    for(i=1;i<10001;i++)
        rem[i]=i;//每只记录的老鼠都是自己
    k=1;
    while(scanf("%d%d",&s[k].weight,&s[k].speed)!=EOF){
        s[k].num=k;
        k++;
    } 
    sort(s+1,s+k,cmp);//排序啦
    for(i=1,m=0;i<k;i++){
        maxn=0;//maxn表示最大的子序列长度 即 找到符合条件最多的老鼠数量
        for(j=1;j<i;j++){
            if(s[i].weight<s[j].weight&&s[j].speed<s[i].speed){
                if(maxn<dp[j]){//此时数量大于记录数量 
                    maxn=dp[j];//把数量赋给maxn 
                    mark=s[j].num;//几下这只老鼠的编号 
                }
            }
            if(maxn)//如果最大数量存在;
                rem[s[i].num]=mark;//将用于比较的老鼠编号和记录的老鼠编号对应记下来
            dp[i]=maxn+1;//每次要更新,如果maxn为零,加上1就是包括自己啦                
            if(m<dp[i]){//m是记录符合条件的最大老鼠数量 
                m=dp[i];
                t=s[i].num;//t是记录最后一只符合条件老鼠的编号,方便输出 
                //因为i是后面的,j是i前面的呀 
            }
        }
    } 
    if(m==1)//当m等于1是即没有符合条件的其他老鼠,那随便哪只都可以啦 
        cout<<1<<endl<<1<<endl;
    else{
        cout<<m<<endl;
        while(rem[t]!=t){//如果此时老鼠编号对应的老鼠不是自己 
            cout<<t<<endl;
            t=rem[t];
        }
        cout<<t<<endl;
    }   
    return 0;
}

转载于:https://www.jianshu.com/p/6c97785186ec

猜你喜欢

转载自blog.csdn.net/weixin_34092370/article/details/91343512