01背包
问题描述:给定n个物体(它们的重量为:w1,w2,…,wn,价值为:v1,v2,…,vn) 和 一个承受重量为W的背包,问怎么选取这些物体,放在背包中(不超过背包的承重),让所取的子集达到最大价值。
- 二维数组实现
- 基本实现
主要考虑两个基本问题
(1)第n个物体不放进背包中;
(2)第n个物体放进背包。
递推式如下:
- 代码实现
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();//商品数量
int m = scanner.nextInt();//背包容量
int v[] = new int[n+1];//每个商品价值
int w[] = new int[n+1];//每个商品重量
for (int i = 1; i <= n; i++) {
v[i] = scanner.nextInt();
}
for (int i = 1; i <= n; i++) {
w[i] = scanner.nextInt();
}
int dp[][] = new int[n + 1][m+1];
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if(j >= w[i]) {
dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j - w[i]] + v[i]);
}
}
}
System.out.println(dp[n][m]);
}
}
- 一维数组实现
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
int v[] = new int[n+1];
int w[] = new int[n+1];
for (int i = 1; i <= n; i++) {
v[i] = scanner.nextInt();
}
for (int i = 1; i <= n; i++) {
w[i] = scanner.nextInt();
}
// int dp[][] = new int[n + 1][m+1];
int dp[] = new int[m+1];
for (int i = 1; i <= n; i++) {
//注意这里是倒序
for (int j = m; j >= w[i]; j--) {
if(j >= w[i]) {
// dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j - w[i]] + v[i]);
dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]);
}
}
}
System.out.println(dp[m]);
}
}
完全背包
问题描述:完全背包是在01背包的基础上加了个条件——这n种物品都有无限的数量可以取,问怎样拿才可以实现价值最大化。
- 基本实现
递推式
- 二维数组实现
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
int v[] = new int[n+1];
int w[] = new int[n+1];
for (int i = 1; i <= n; i++) {
v[i] = scanner.nextInt();
}
for (int i = 1; i <= n; i++) {
w[i] = scanner.nextInt();
}
int dp[][] = new int[n + 1][m+1];
// int dp[] = new int[m+1];
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if(j / w[i] >= 1) { //可以放置一件或一件以上的物品时
int max = 0;
for (int k = 1; k <= j / w[i]; k++) {//背包可以放置同一件物品多件
if(dp[i-1][j - k * w[i]] + k * v[i] > max) {
max = dp[i-1][j - k * w[i]] + k * v[i];
}
}
dp[i][j] = Math.max(dp[i-1][j], max);
// dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]);
}
}
}
System.out.println(dp[n][m]);
}
}
- 一维数组实现
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
int v[] = new int[n+1];
int w[] = new int[n+1];
for (int i = 1; i <= n; i++) {
v[i] = scanner.nextInt();
}
for (int i = 1; i <= n; i++) {
w[i] = scanner.nextInt();
}
// int dp[][] = new int[n + 1][m+1];
int dp[] = new int[m+1];
for (int i = 1; i <= n; i++) {
for (int j = w[i]; j <= m; j++) {
// if(j / w[i] >= 1) {
// int max = 0;
// for (int k = 1; k <= j / w[i]; k++) {//背包可以放置同一件物品多件
// if(dp[j - k * w[i]] + k * v[i] > max) {
// max = dp[j - k * w[i]] + k * v[i];
// }
// }
// dp[i][j] = Math.max(dp[i-1][j], max);
dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]);
// }
}
}
System.out.println(dp[m]);
}
}
多种背包
问题描述:多重背包是在01背包的基础上,加了个条件:第 i 件物品有ni件。
- 基本实现
代码实现如下所示,代码与完全背包的区别除了多了个表示物品个数的数组n[ ]之外,只在内循环的控制条件那里。
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
int v[] = new int[n+1];
int w[] = new int[n+1];
int amout[] = new int[n + 1];
for (int i = 1; i <= n; i++) {
v[i] = scanner.nextInt();
}
for (int i = 1; i <= n; i++) {
w[i] = scanner.nextInt();
}
for (int i = 1; i <= n; i++) {
amout[i] = scanner.nextInt();
}
int dp[][] = new int[n + 1][m+1];
// int dp[] = new int[m+1];
for (int i = 1; i <= n; i++) {
for (int j = w[i]; j <= m; j++) {
if(j / w[i] >= 1) {
int max = 0;
for (int k = 1; k <= j / w[i] && k <= amout[i]; k++) {//背包可以放置同一件物品多件
if(dp[i-1][j - k * w[i]] + k * v[i] > max) {
max = dp[i-1][j - k * w[i]] + k * v[i];
}
}
dp[i][j] = Math.max(dp[i-1][j], max);
// dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]);
}
}
}
System.out.println(dp[n][m]);
}
}