0/1 背包裸题:dp[j] 表示时间上限 j 能采到的最大价值,容量倒序转移保证每株草药只用一次,dp[T] 即答案。
OJ: roj
题目 ID: 1290
难度:入门
标签:DP01背包动态规划
创建: 2026-09-30 03:38
更新: 2026-10-04 22:12
题目描述
辰辰进山洞采药,总时间上限
思路
一维 0/1 背包:dp[j] 表示时间上限 dp[j] = max(dp[j], dp[j - cost] + value),倒序保证每株只入一次;答案为 dp[T]。
参考代码
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 03:38
# update_at: 2026-09-30 03:38
import sys
def solve() -> None:
data = iter(map(int, sys.stdin.buffer.read().split()))
limit = next(data) # 题面的 T:可用于采药的总时间
count = next(data) # 题面的 M:草药株数
# dp[j] = 限定时间 j 内能采到的最大总价值;容量维度倒序保证每株草药只用一次
dp = [0] * (limit + 1)
for _ in range(count):
cost = next(data) # 采摘这株草药需要的时间
value = next(data) # 这株草药的价值
for j in range(limit, cost - 1, -1):
dp[j] = max(dp[j], dp[j - cost] + value)
print(dp[limit])
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-04 22:12
* update_at: 2026-10-04 22:12
*/
// main.cpp:采药(roj 1290)的 0/1 背包一维滚动解。
// 容量上限 T <= 1000,物品数 M <= 100,单件花费与价值均在 [1,100],结果用 long long 兜住。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXT = 1005; // 容量上限 + 1,足够放下题目给的最大 T
ll T; // 总可用时间(背包容量)
ll M; // 草药总数
ll dp[MAXT]; // dp[j] = 限定时间 j 内能采到的最大价值;只用一维滚动数组
void read_input() {
cin >> T >> M;
}
void solve() {
// 初始化:所有容量下的最优价值都为 0。
for (ll j = 0; j <= T; j++) dp[j] = 0;
for (ll i = 0; i < M; i++) {
ll cost; // 这株草药的采摘时间
ll value; // 这株草药的价值
cin >> cost >> value;
// 容量倒序扫描,保证 dp[j - cost] 还是上一轮(第 i-1 株)的结果,
// 从而实现"每株草药至多取一次"的 0/1 语义。
for (ll j = T; j >= cost; j--) {
dp[j] = max(dp[j], dp[j - cost] + value);
}
}
cout << dp[T] << "\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
read_input();
solve();
return 0;
}