最长上升子序列模型(1)

怪盗基德的滑翔翼在这里插入图片描述

数据范围
1≤K≤100,
1≤N≤100,
0<h<10000

输入样例:
3
8
300 207 155 299 298 170 158 65
8
65 158 170 298 299 155 207 300
10
2 1 3 4 5 6 7 8 9 10
输出样例:
6
6
9

解法:求出正向和逆向的最大上升子序列,取最大值

#include <iostream>

using namespace std;

const int N=110;

int f[N],a[N],g[N],n;

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i];
        int res=0;
        for(int i=1;i<=n;i++)
        {
            f[i]=g[i]=1;
            for(int j=1;j<=i;j++)
                if(a[j]<a[i])
                    f[i]=max(f[i],f[j]+1);
                else if(a[i]<a[j])
                    g[i]=max(g[i],g[j]+1);
            res=max(res,f[i]);
            res=max(res,g[i]);
        }
        
        cout<<res<<endl;
    }
    return 0;
}

登山
在这里插入图片描述

数据范围
2≤N≤1000

输入样例:
8
186 186 150 200 160 130 197 220
输出样例:
4

解法:求出以每个点为结尾的最大上升与下降子序列和的最大值,因此分别正逆求最大上升子序列,再逐点取最值即可

#include <iostream>

using namespace std;

const int N=1010;

int n,f[N],a[N],g[N];

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++)
    {
        f[i]=1;
        for(int j=1;j<i;j++)
            if(a[i]>a[j])
                f[i]=max(f[i],f[j]+1);
    }
    for(int i=n;i;i--)
    {
        g[i]=1;
        for(int j=n;j>i;j--)
            if(a[j]<a[i])
                g[i]=max(g[i],g[j]+1);
    }
    int res=0;
    for(int i=1;i<=n;i++)
    {
        res=max(res,f[i]+g[i]-1);  //这里注意要减一,因为当前点同时算在 f[i] g[i]中
    }
    cout<<res<<endl;
    return 0;
}

合唱队形
在这里插入图片描述
数据范围
2≤N≤100,

130≤Ti≤230
输入样例:
8
186 186 150 200 160 130 197 220
输出样例:
4

解法:与上一题类似,求出最大上升与下降子序列和的最大值,再用总数减去即可

#include <iostream>

using namespace std;

const int N=110;

int f[N],g[N],a[N],n;

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++)
    {
        f[i]=1;
        for(int j=1;j<i;j++)
            if(a[j]<a[i])
                f[i]=max(f[i],f[j]+1);
    }
    for(int i=n;i;i--)
    {
        g[i]=1;
        for(int j=n;j>i;j--)
            if(a[j]<a[i])
                g[i]=max(g[i],g[j]+1);
    }
    int res=0;
    for(int i=1;i<=n;i++) res=max(res,f[i]+g[i]-1);
    cout<<n-res<<endl;
    return 0;
}

友好城市
在这里插入图片描述
数据范围
1≤N≤5000,
0≤xi≤10000

输入样例:
7
22 4
2 6
10 3
15 12
9 8
17 17
4 2
输出样例:
4

解法:此题做法较为特殊,先对某一岸的城市进行排序,再按照排序的顺序找对岸城市的最大上升子序列

#include <iostream>
#include <algorithm>

using namespace std;

const int N=5010;

typedef pair<int,int> PII;  //直接用 pair 存储便于排序

int f[N],n;
PII a[N];

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i].first>>a[i].second;
    sort(a+1,a+1+n);
    int res=0;
    for(int i=1;i<=n;i++)
    {
        f[i]=1;
        for(int j=1;j<i;j++)
            if(a[j].second<a[i].second)
                f[i]=max(f[i],f[j]+1);
        res=max(f[i],res);
    }
    cout<<res<<endl;
    return 0;
}

最大上升子序列和
在这里插入图片描述
数据范围
1≤N≤1000

输入样例:
7
1 7 3 5 9 4 8
输出样例:
18

解法:与求最大上升子序列相似

#include <iostream>

using namespace std;

const int N=1010;

int n,f[N],a[N];

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    int res=0;
    for(int i=1;i<=n;i++)
    {
        f[i]=a[i];	// f[i] 存储的是以第 i 个数结尾的最大上升子序列和,因此要初始化为 a[i]
        for(int j=1;j<i;j++)
            if(a[j]<a[i])
                f[i]=max(f[i],f[j]+a[i]);
        res=max(f[i],res);
    }
    cout<<res<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值