### 0-1 背包问题的 Java 实现解决方案
#### 动态规划方法
动态规划是一种经典的解决 0-1 背包问题的方法。它通过构建一个二维数组 `dp` 来存储子问题的结果,其中 `dp[i][j]` 表示前 `i` 个物品在背包容量为 `j` 的情况下的最大价值。
以下是基于动态规划的 Java 实现:
```java
public class Knapsack {
public static int knapSack(int W, int[] wt, int[] val, int n) {
int[][] dp = new int[n + 1][W + 1];
for (int i = 0; i <= n; i++) {
for (int w = 0; w <= W; w++) {
if (i == 0 || w == 0) {
dp[i][w] = 0;
} else if (wt[i - 1] <= w) {
dp[i][w] = Math.max(val[i - 1] + dp[i - 1][w - wt[i - 1]], dp[i - 1][w]);
} else {
dp[i][w] = dp[i - 1][w];
}
}
}
return dp[n][W];
}
public static void main(String[] args) {
int[] val = {60, 100, 120};
int[] wt = {10, 20, 30};
int W = 50;
int n = val.length;
System.out.println(knapSack(W, wt, val, n)); // 输出结果应为 220
}
}
```
上述代码实现了动态规划的核心逻辑[^4]。通过迭代计算每个状态的最大价值,最终得到全局最优解。
---
#### 递归方法
递归方法可以通过回溯的思想解决问题。对于每一个物品,可以选择将其放入背包或者不放入背包,从而形成两种可能的状态树。递归方法的时间复杂度较高,但由于其简单直观,在某些场景下仍然具有应用价值。
以下是基于递归的 Java 实现:
```java
public class RecursiveKnapsack {
public static int knapSack(int W, int[] wt, int[] val, int n) {
if (n == 0 || W == 0) {
return 0;
}
if (wt[n - 1] > W) {
return knapSack(W, wt, val, n - 1);
} else {
return Math.max(
val[n - 1] + knapSack(W - wt[n - 1], wt, val, n - 1),
knapSack(W, wt, val, n - 1)
);
}
}
public static void main(String[] args) {
int[] val = {60, 100, 120};
int[] wt = {10, 20, 30};
int W = 50;
int n = val.length;
System.out.println(knapSack(W, wt, val, n)); // 输出结果应为 220
}
}
```
此代码展示了递归方法的基本思想[^1]。尽管这种方法易于理解,但在大规模数据集上可能会遇到性能瓶颈。
---
#### 分支限界法
分支限界法通过对搜索空间进行剪枝优化,减少不必要的计算量。该方法通常用于处理较大规模的数据集,并能有效降低时间复杂度。
以下是一个简单的分支限界法实现思路:
```java
import java.util.*;
public class BranchAndBoundKnapsack {
private static class Node implements Comparable<Node> {
int level, profit, bound, weight;
@Override
public int compareTo(Node other) {
return Double.compare(other.bound, this.bound); // 按照边界值降序排列
}
}
public static int solveKnapsack(int capacity, int[] weights, int[] values, int itemCount) {
PriorityQueue<Node> pq = new PriorityQueue<>();
double totalProfit = Arrays.stream(values).sum();
Node root = new Node();
root.level = -1;
root.profit = 0;
root.weight = 0;
computeBound(root, capacity, weights, values, itemCount);
pq.add(root);
while (!pq.isEmpty()) {
Node node = pq.poll();
if (node.bound > maxProfit && node.weight <= capacity) {
maxProfit = node.profit;
}
if (node.level >= itemCount - 1) continue;
Node nextInclude = new Node();
nextInclude.level = node.level + 1;
nextInclude.weight = node.weight + weights[nextInclude.level];
nextInclude.profit = node.profit + values[nextInclude.level];
if (nextInclude.weight <= capacity && nextInclude.profit > maxProfit) {
maxProfit = nextInclude.profit;
}
computeBound(nextInclude, capacity, weights, values, itemCount);
if (nextInclude.bound > maxProfit) {
pq.add(nextInclude);
}
Node nextExclude = new Node();
nextExclude.level = node.level + 1;
nextExclude.weight = node.weight;
nextExclude.profit = node.profit;
computeBound(nextExclude, capacity, weights, values, itemCount);
if (nextExclude.bound > maxProfit) {
pq.add(nextExclude);
}
}
return maxProfit;
}
private static void computeBound(Node u, int cap, int[] wt, int[] val, int n) {
if (u.weight >= cap) {
u.bound = 0;
return;
}
u.bound = u.profit;
int j = u.level + 1;
int totweight = u.weight;
while ((j < n) && (totweight + wt[j] <= cap)) {
totweight += wt[j];
u.bound += val[j];
j++;
}
if (j < n) {
u.bound += (cap - totweight) * (val[j] / (double) wt[j]);
}
}
private static int maxProfit = Integer.MIN_VALUE;
public static void main(String[] args) {
int[] val = {60, 100, 120};
int[] wt = {10, 20, 30};
int W = 50;
int n = val.length;
System.out.println(solveKnapsack(W, wt, val, n)); // 输出结果应为 220
}
}
```
这段代码采用了优先队列来管理节点的选择顺序,并通过边界值计算加速收敛过程[^5]。
---