对于一维背包问题,注意区分该问题的下面这三种情况,二维背包问题也是类似的处理方式。
(1) 体积至多是v
时的最小/大值
全部初始化为0,且保证v大于等于0。
代表题目:AcWing 423.采药,其代码如下:
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
int M = sc.nextInt();
int[] time = new int[M + 10];
int[] value = new int[M + 10];
for(int i = 1; i <= M; i ++){
time[i] = sc.nextInt();
value[i] = sc.nextInt();
}
// dp:01背包问题
int[] f = new int[T + 10];
for(int i = 1; i <= M; i ++)
for(int j = T; j >= time[i]; j --){
f[j] = Math.max(f[j], f[j - time[i]] + value[i]);
}
System.out.println(f[T]);
}
}
(2) 体积恰好是v
时的最小/大值
f[0]初始化为0,其余初始化为正/负无穷(分别对应题目问的最小/最大,代表不合法状态,不应该被选取),且保证v大于等于0。
代表题目:LeetCode 322.零钱兑换,其代码如下:
class Solution {
public int coinChange(int[] coins, int amount) {
// 完全背包问题
int n = coins.length;
int[] f = new int[amount + 10];
// 初始化
for(int i = 1; i < f.length; i ++) f[i] = 1 << 25;
f[0] = 0;
// DP,状态计算
for(int i = 1; i <= n; i ++)
for(int j = coins[i - 1]; j <= amount; j ++){
f[j] = Math.min(f[j], f[j - coins[i - 1]] + 1);
}
if(f[amount] >= 1 << 25) return -1;
else return f[amount];
}
}
(3) 体积至少是v
时的最小/大值
f[0]初始化为0,其余初始化为正/负无穷(分别对应题目问的最小/最大,代表不合法状态,不应该被选取),无需保证v大于等于0。
代表题目:AcWing 1020.潜水员,其代码如下:
import java.util.*;
public class Main{
static int M = 30;
static int N = 90;
static int K = 1010;
static int[][] f = new int[M][N];
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int m = sc.nextInt();
int n = sc.nextInt();
int k = sc.nextInt();
// 初始化
for(int i = 0; i < M; i ++)
for(int j = 0; j < N; j ++)
f[i][j] = 1 << 25;
f[0][0] = 0;
// dp,状态计算
for(int i = 1; i <= k; i ++){
int a = sc.nextInt();
int b = sc.nextInt();
int c = sc.nextInt();
for(int j = m; j >= 0; j --)
for(int s = n; s >= 0; s --)
f[j][s] = Math.min(f[j][s], f[Math.max(0, j - a)][Math.max(0, s - b)] + c);
}
System.out.println(f[m][n]);
}
}