算法acwing 01背包

这篇博客介绍了01背包问题的解决方法,通过动态规划优化代码,实现背包容积限制下物品价值最大化的求解。输入物品数量、体积和价值,输出最大价值。示例输入4件物品,背包容积5,输出最大价值8。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。

第 i 件物品的体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。

接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。

输出格式
输出一个整数,表示最大价值。

数据范围

0<N,V≤1000 0<vi,wi≤1000

输入样例

4 5 1 2 2 4 3 4 4 5

输出样例:

8

题解

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 1010;

int n, m;
int f[N][N];
int v[N], w[N];

int main() {
    //题目输入  物品数量n, 背包容积m
    cin >> n >> m;
    for (int i = 1; i <= n; i++)cin >> v[i] >> w[i];

    for (int i = 1; i <= n; i++) 
        for (int j = 1; j <= m; j++) {
            //f[i][j] = f[i - 1][j];
            if (v[i] <= j)
                f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
        }

    int res = 0;
    for (int j = 0; j <= m; j++)res = max(res, f[n][j]);

    cout << res;
    return 0;
}

代码优化

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 1010;

int n, m;
int f[N];
int v[N], w[N];
//二维表示前i个物品,所占总体积为j 时的最大价值
//一维表示f[i]表示体积是i的情况下最大价值是多少
int main() {
    //题目输入  物品数量n, 背包容积m
    cin >> n >> m;
    for (int i = 1; i <= n; i++)cin >> v[i] >> w[i];

    for (int i = 1; i <= n; i++) 
        for (int j = m; j >=v[i]; j--) 
            f[j] = max(f[j], f[j - v[i]] + w[i]);

    cout << f[m];
    return 0;
}

第一次接触01背包问题,还有点不熟悉,如果不妥之处,请指正。

### 关于 AcWing 算法基础课中的 Python 实现动态规划背包问题模板 以下是基于多重背包问题的朴素版本实现的一个通用 DP 背包问题代码模板。此模板适用于处理物品数量有限制的情况,即每个物品最多可以选择 `s[i]` 次。 #### 代码模板 ```python # 定义最大容量和物品数 N = 110 # 物品数量的最大值加一 f = [0] * N # 初始化状态转移方程数组 def multiple_knapsack(n, m, v, w, s): """ :param n: 总共的物品数目 :param m: 背包总容量 :param v: 列表,存储第i件物品的价值 :param w: 列表,存储第i件物品的重量 :param s: 列表,存储第i件物品的数量上限 :return: 返回能够获得的最大价值 """ for i in range(1, n + 1): # 遍历每一个物品 for j in range(m, 0, -1): # 倒序遍历背包剩余空间 k = 0 while k * v[i] <= j and k <= s[i]: # 添加约束条件k<=s[i] f[j] = max(f[j], f[j - k * v[i]] + k * w[i]) k += 1 return f[m] if __name__ == "__main__": n, m = map(int, input().split()) # 输入物品总数和背包容量 v, w, s = [0] * (n + 1), [0] * (n + 1), [0] * (n + 1) # 存储v,w,s for i in range(1, n + 1): v[i], w[i], s[i] = map(int, input().split()) result = multiple_knapsack(n, m, v, w, s) print(result) ``` 上述代码实现了多重背包问题的核心逻辑[^1]。通过倒序更新的方式避免重复计算,并引入了一个额外变量 `k` 来控制当前物品的选择次数不超过其允许的最大值 `s[i]`。 --- #### 区间动态规划扩展说明 如果遇到更复杂的场景,比如需要记录最优解路径或者涉及区间划分的问题,则可以参考加分二叉树的做法[^3]。此时通常会增加辅助数据结构用于保存中间结果或决策过程。 例如,在某些情况下可能需要用到二维数组来表示子区间的最佳得分情况: ```python dp = [[0] * N for _ in range(N)] # dp[l][r] 表示从l到r这个范围内的最大收益 addition_info = [[None] * N for _ in range(N)] # 记录分割点或其他附加信息 ``` 这种设计模式特别适合那些不仅关注最终答案还关心具体构成细节的应用场合。 --- #### 更高效的优化方法探讨 对于大规模输入的数据集而言,朴素版的时间复杂度较高(O(n*m*sum(s)))。因此实际应用时常采用单调队列等高级技巧进一步降低运行时间开销[^2]。 然而初学者建议先掌握基本形式再逐步深入学习改进策略。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值