蓝桥赛前复习7:线性DP&&背包DP

线性DP:最长公共子序列 (LCS)

最长公共子序列

题目描述

给定一个长度为 NN 数组 aa 和一个长度为 MM 的数组 bb。

请你求出它们的最长公共子序列长度为多少。

输入描述

输入第一行包含两个整数 N,MN,M,分别表示数组 aa 和 bb 的长度。

第二行包含 NN 个整数 a1,a2,...,ana1​,a2​,...,an​。

第三行包含 MM 个整数 b1,b2,...,bnb1​,b2​,...,bn​。

1≤N,M≤1031≤N,M≤103,1≤ai,bi≤1091≤ai​,bi​≤109。

输出描述

输出一行整数表示答案。

输入输出样例

示例 1

输入

5 6
1 2 3 4 5
2 3 2 1 4 5

输出

4

 

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int N, M;
    cin >> N >> M;
    
    vector<int> a(N), b(M);
    
    for (int i = 0; i < N; ++i) cin >> a[i];
    for (int i = 0; i < M; ++i) cin >> b[i];
    
    // dp[i][j]表示a[0..i-1]和b[0..j-1]的最长公共子序列长度
    vector<vector<int>> dp(N + 1, vector<int>(M + 1, 0));
    
    // 动态规划求解
    for (int i = 1; i <= N; ++i) {
        for (int j = 1; j <= M; ++j) {
            if (a[i - 1] == b[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1] + 1;
            } else {
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }
    
    // 最长公共子序列的长度在dp[N][M]中
    cout << dp[N][M] << endl;
    
    return 0;
}

 线性DP:最长递增子序列(LIS)

蓝桥骑士

题目描述

小明是蓝桥王国的骑士,他喜欢不断突破自我。

这天蓝桥国王给他安排了 NN 个对手,他们的战力值分别为 a1,a2,...,ana1​,a2​,...,an​,且按顺序阻挡在小明的前方。对于这些对手小明可以选择挑战,也可以选择避战。

身为高傲的骑士,小明从不走回头路,且只愿意挑战战力值越来越高的对手。

请你算算小明最多会挑战多少名对手。

输入描述

输入第一行包含一个整数 NN,表示对手的个数。

第二行包含 NN 个整数 a1,a2,...,ana1​,a2​,...,an​,分别表示对手的战力值。

1≤N≤3×1051≤N≤3×105,1≤ai≤1091≤ai​≤109。

输出描述

输出一行整数表示答案。

输入输出样例

示例 1

输入

6
1 4 2 2 5 6

输出

4
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    int N;
    cin >> N;
    vector<int> a(N);
    
    for (int i = 0; i < N; ++i) {
        cin >> a[i];
    }
    
    // lis数组存储的是递增子序列的最后一个元素
    vector<int> lis;
    
    for (int i = 0; i < N; ++i) {
        // 使用lower_bound查找a[i]应该插入的位置
        auto it = lower_bound(lis.begin(), lis.end(), a[i]);
        
        if (it == lis.end()) {
            // 如果没有找到合适的位置,就将a[i]加入lis的末尾
            lis.push_back(a[i]);
        } else {
            // 否则,替换掉最小的一个大于或等于a[i]的元素
            *it = a[i];
        }
    }
    
    // lis的大小即为最长递增子序列的长度
    cout << lis.size() << endl;
    
    return 0;
}

 

 背包DP:0/1 背包问题

题目描述

小明有一个容量为 VV 的背包。

这天他去商场购物,商场一共有 NN 件物品,第 ii 件物品的体积为 wiwi​,价值为 vivi​。

小明想知道在购买的物品总体积不超过 VV 的情况下所能获得的最大价值为多少,请你帮他算算。

输入描述

输入第 11 行包含两个正整数 N,VN,V,表示商场物品的数量和小明的背包容量。

第 2∼N+12∼N+1 行包含 22 个正整数 w,vw,v,表示物品的体积和价值。

1≤N≤1021≤N≤102,1≤V≤1031≤V≤103,1≤wi,vi≤1031≤wi​,vi​≤103。

输出描述

输出一行整数表示小明所能获得的最大价值。

输入输出样例

示例 1

输入

5 20
1 6
2 5
3 8
5 15
3 3 

输出

37
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    int N, V;
    cin >> N >> V;
    
    // dp[i]表示容量为i的背包能装的最大价值
    vector<int> dp(V + 1, 0);
    
    // 输入物品的体积和价值
    for (int i = 0; i < N; ++i) {
        int w, v;
        cin >> w >> v;
        
        // 倒序更新dp数组,避免重复使用物品
        for (int j = V; j >= w; --j) {
            dp[j] = max(dp[j], dp[j - w] + v);
        }
    }
    
    // 最终的最大价值为dp[V]
    cout << dp[V] << endl;
    
    return 0;
}

 

 背包DP:完全背包问题

问题描述

有 NN 件物品和一个体积为 MM 的背包。第 ii 个物品的体积为 vivi​,价值为 wiwi​。每件物品可以使用无限次。

请问可以通过什么样的方式选择物品,使得物品总体积不超过 MM 的情况下总价值最大,输出这个最大价值即可。

输入格式

第一行输入两个正整数 N,MN,M。(1≤N,M≤1000)(1≤N,M≤1000)

接下来 NN 行,每行输入两个整数 vi,wivi​,wi​。(0≤vi,wi≤1000)(0≤vi​,wi​≤1000)

输出格式

输出一个整数,表示符合题目要求的最大价值。

样例输入

4 5
1 2
2 4
3 4
4 5

样例输出

10

说明

你可以选择 11 个第一个物品和 22 个第二个物品。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    int N, M;
    cin >> N >> M;
    
    vector<int> dp(M + 1, 0); // dp[i]表示容量为i的背包能获得的最大价值
    
    // 输入物品的体积和价值
    for (int i = 0; i < N; ++i) {
        int v, w;
        cin >> v >> w;
        
        // 完全背包:从v到M遍历更新dp数组
        for (int j = v; j <= M; ++j) {
            dp[j] = max(dp[j], dp[j - v] + w);
        }
    }
    
    // 最终的最大价值为dp[M]
    cout << dp[M] << endl;
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值