一维滚动 0/1 背包 DP:逐件物品倒序扫描容量,dp[v]=max(dp[v],dp[v-W]+C),答案为 dp[M]。
OJ: roj
题目 ID: 1267
难度:普及-
标签:动态规划背包01背包python
创建: 2026-09-30 02:38
更新: 2026-10-05 07:39
题目描述
一个旅行者有一个最多能装 10 4,2 1,3 3,4 5,7 9(每行一项);样例输出:12(选物品 2 和 4,重量
思路
一维 0/1 背包:
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-09-30 02:38
# update_at: 2026-09-30 02:38
import sys
def solve() -> None:
data = iter(map(int, sys.stdin.buffer.read().split()))
capacity, count = next(data), next(data) # 题面的 M 与 N
items = [(next(data), next(data)) for _ in range(count)] # 每件的 (W_i, C_i)
# dp[v] = 已处理物品中,总重量不超过 v 时的最大价值;不要求装满,故初值全 0
dp = [0] * (capacity + 1)
for weight, value in items:
# 容量必须倒序扫描:读到的 dp[v - weight] 还是"没考虑本物品"的旧值,
# 本物品至多被选一次(正序会读到本轮刚更新的值,那就成了完全背包)。
# weight > capacity 时 range 为空,装不下的物品自动被跳过。
for v in range(capacity, weight - 1, -1):
dp[v] = max(dp[v], dp[v - weight] + value)
print(dp[capacity])
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-05 07:39
* update_at: 2026-10-05 07:39
*/
// 01 背包:一维滚动数组,容量倒序扫描保证每件物品最多选一次。
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 35; // 物品数上限
const int MAXM = 205; // 背包容量上限
ll m, n; // 背包容量、物品数量
ll w[MAXN], c[MAXN]; // w[i] 第 i 件物品重量,c[i] 第 i 件物品价值
ll dp[MAXM]; // dp[v]:容量不超过 v 时能获得的最大价值
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> m >> n;
for (int i = 1; i <= n; i++)
cin >> w[i] >> c[i];
// 转移:dp[v] = max(dp[v], dp[v-w]+c),v 必须从大到小扫描。
// 倒序时 dp[v-w] 还没被本轮更新,是"没考虑本物品"的旧值;
// 正序会让同一件物品被反复装入,变成完全背包。
for (int i = 1; i <= n; i++)
for (int v = (int)m; v >= (int)w[i]; v--)
dp[v] = max(dp[v], dp[v - w[i]] + c[i]);
cout << dp[m] << endl;
return 0;
}