【模板】01背包
思路
经典的 01 背包模板题,但这道题要求输出两个答案:
- 不要求装满:背包容量为
,在不超过容量的前提下,能装的最大价值是多少?
- 恰好装满:背包容量恰好为
时,能装的最大价值是多少?如果装不满就输出 0。
01 背包基础
01 背包的核心:每个物品只有「选」或「不选」两种状态。
定义 表示容量为
时能获得的最大价值。对于每个物品
,从大到小遍历容量(这样保证每个物品只选一次):
$$
两问的区别在于初始化
这道题的精髓就在初始化:
第一问(不要求装满): 全部初始化为 0。因为任何容量下,「什么都不装」也是一种合法方案,价值为 0。
第二问(恰好装满):只有 是合法的(容量为 0 恰好装满),其余
初始化为
(或
),表示这些状态目前不可达。转移时只从合法状态(
)转移过来,这样最终
就说明无法恰好装满。
为什么这样就能保证「恰好装满」?因为初始时只有 是合法起点,所有的状态都是从
一步步转移来的,每一步都恰好用掉了对应的体积,所以
合法就意味着存在一组物品体积之和恰好等于
。
复杂度
- 时间复杂度:
- 空间复杂度:
(滚动数组优化)
代码
#include <bits/stdc++.h>
using namespace std;
int main(){
int n, V;
scanf("%d%d", &n, &V);
vector<int> v(n), w(n);
for(int i = 0; i < n; i++) scanf("%d%d", &v[i], &w[i]);
// dp1: 不要求装满
vector<int> dp1(V+1, 0);
// dp2: 恰好装满,-1 表示不可达
vector<int> dp2(V+1, -1);
dp2[0] = 0;
for(int i = 0; i < n; i++){
for(int j = V; j >= v[i]; j--){
dp1[j] = max(dp1[j], dp1[j - v[i]] + w[i]);
if(dp2[j - v[i]] >= 0){
dp2[j] = max(dp2[j], dp2[j - v[i]] + w[i]);
}
}
}
printf("%d\n", dp1[V]);
printf("%d\n", dp2[V] < 0 ? 0 : dp2[V]);
return 0;
}
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
int V = Integer.parseInt(st.nextToken());
int[] v = new int[n], w = new int[n];
for (int i = 0; i < n; i++) {
st = new StringTokenizer(br.readLine());
v[i] = Integer.parseInt(st.nextToken());
w[i] = Integer.parseInt(st.nextToken());
}
int[] dp1 = new int[V + 1]; // 不要求装满
int[] dp2 = new int[V + 1]; // 恰好装满
Arrays.fill(dp2, -1);
dp2[0] = 0;
for (int i = 0; i < n; i++) {
for (int j = V; j >= v[i]; j--) {
dp1[j] = Math.max(dp1[j], dp1[j - v[i]] + w[i]);
if (dp2[j - v[i]] >= 0) {
dp2[j] = Math.max(dp2[j], dp2[j - v[i]] + w[i]);
}
}
}
System.out.println(dp1[V]);
System.out.println(dp2[V] < 0 ? 0 : dp2[V]);
}
}
import sys
input = sys.stdin.readline
def main():
n, V = map(int, input().split())
items = []
for _ in range(n):
vi, wi = map(int, input().split())
items.append((vi, wi))
dp1 = [0] * (V + 1)
dp2 = [-1] * (V + 1)
dp2[0] = 0
for vi, wi in items:
for j in range(V, vi - 1, -1):
if dp1[j - vi] + wi > dp1[j]:
dp1[j] = dp1[j - vi] + wi
if dp2[j - vi] >= 0:
val = dp2[j - vi] + wi
if val > dp2[j]:
dp2[j] = val
print(dp1[V])
print(dp2[V] if dp2[V] >= 0 else 0)
main()
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin });
const lines = [];
rl.on('line', l => lines.push(l));
rl.on('close', () => {
const [n, V] = lines[0].split(' ').map(Number);
const v = [], w = [];
for (let i = 1; i <= n; i++) {
const parts = lines[i].split(' ').map(Number);
v.push(parts[0]);
w.push(parts[1]);
}
const dp1 = new Array(V + 1).fill(0);
const dp2 = new Array(V + 1).fill(-1);
dp2[0] = 0;
for (let i = 0; i < n; i++) {
for (let j = V; j >= v[i]; j--) {
dp1[j] = Math.max(dp1[j], dp1[j - v[i]] + w[i]);
if (dp2[j - v[i]] >= 0) {
dp2[j] = Math.max(dp2[j], dp2[j - v[i]] + w[i]);
}
}
}
console.log(dp1[V]);
console.log(dp2[V] < 0 ? 0 : dp2[V]);
});



京公网安备 11010502036488号