问题
三个物品他们的编号,重量和价值如下。1个背包能够称重30公斤,求装入的物品的最大价值
总结
广度优先搜索解空间树:结点是状态,分支是选择这个状态
- 一个物品产生两种状态(结点):加入状态,不加入状态
- 分支代表:你选择那种状态,你可以选择加入背包,也可以选择不加入背包
- 选择加入背包的条件:加入了不超重
- 选择不加入背包的条件:将来加入的物品更有价值
分枝:左分枝-加入背包,右分枝-不加入背包 限界:限界函数,限制走的分支,没有价值的分支不会往下走,走这个分支一定得不到解就不走
分枝限界法
分枝限界法:广度优先搜索解空间树 0. 解空间树:
- 左分枝代表选择,右分枝代表不选择
- 左孩子代表加入了第i个物品,右孩子代表没有加入第i个物品
- 选择不选择加入第i个物品:1~i-1物品重量之和+i物品重量<=背包可承受重量
- 活结点表:普通队列
- 限界函数:
- 当前结点是不是有前景的结点,从当前结点扩展下去能够获得更大价值
- 求最大价值是最大值问题,使用上界函数;当前结点的极大价值>当前最大价值,这个结点是有发展前景的结点,将这个结点放入活结点表
- 确定解向量的分量:
- 存储解向量的分量。例如,01背包问题的1个解的分量是选择的物品
- 当前结点包含的解向量,保存从根结点到该节点的路径
对比回溯法
回溯法 | 分枝限界法 |
---|
回溯法使用栈进行DFS | 分枝限界法使用队列进行BFS | 回溯法可以找到所有解 | 分枝限界法只能找到1个解(最优解) | 回溯法所有结点都会被遍历 | 分枝限界法每个结点只有1次成为活结点的机会 |
代码
package xcrj.kchalgorithm.branchBound;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
public class Knapsack {
static class Node {
private int i;
private int no;
private int weight;
private double value;
private int[] xs = new int[n + 1];
private double ubValue;
public Node() {
}
public Node(int i, int no, int weight, int value, int[] xs, double ubValue) {
this.i = i;
this.no = no;
this.weight = weight;
this.value = value;
this.xs = xs;
this.ubValue = ubValue;
}
}
private static int n = 3;
private static int availableWeight = 30;
private static int[] weights = {0, 16, 15, 15};
private static double[] values = {0, 45, 25, 25};
private static double maxValue = Double.MIN_VALUE;
private static int[] opitimalXs = new int[n + 1];
private static int tatalNode = 1;
public static void valueUpBound(Node node) {
int sumWeight = node.weight;
double sumValue = node.value;
int i = node.i + 1;
while (i <= n && (sumWeight + weights[i] <= availableWeight)) {
sumWeight += weights[i];
sumValue += values[i];
i++;
}
if (i <= n) {
node.ubValue = sumValue + (availableWeight - sumWeight) * (values[i] / weights[i]);
} else {
node.ubValue = sumValue;
}
}
public static void enQueue(Node node, Queue<Node> que) {
if (node.i == n) {
if (node.value > maxValue) {
maxValue = node.value;
for (int j = 1; j <= n; j++) {
opitimalXs[j] = node.xs[j];
}
}
} else {
que.add(node);
}
}
public static void bfs() {
Queue<Node> que = new LinkedList<>();
Node node = new Node();
node.i = 0;
node.no = tatalNode++;
node.value = 0.0;
for (int j = 1; j <= n; j++) node.xs[j] = 0;
valueUpBound(node);
que.add(node);
while (!que.isEmpty()) {
Node nodeHead = que.poll();
if (nodeHead.weight + weights[nodeHead.i + 1] <= availableWeight) {
Node nodeLeft = new Node();
nodeLeft.i = nodeHead.i + 1;
nodeLeft.no = tatalNode++;
nodeLeft.weight = nodeHead.weight + weights[nodeLeft.i];
nodeLeft.value = nodeHead.value + values[nodeLeft.i];
for (int j = 1; j <= n; j++) nodeLeft.xs[j] = nodeHead.xs[j];
nodeLeft.xs[nodeLeft.i] = 1;
valueUpBound(nodeLeft);
enQueue(nodeLeft, que);
}
Node nodeRight = new Node();
nodeRight.i = nodeHead.i + 1;
nodeRight.no = tatalNode++;
nodeRight.weight = nodeHead.weight;
nodeRight.value = nodeHead.value;
for (int j = 1; j <= n; j++) nodeRight.xs[j] = nodeHead.xs[j];
nodeRight.xs[nodeRight.i] = 0;
valueUpBound(nodeRight);
if (nodeRight.ubValue > maxValue) {
enQueue(nodeRight, que);
}
}
}
public static void main(String[] args) {
bfs();
System.out.println("最大价值:" + maxValue);
System.out.println("装入物品:" + Arrays.toString(opitimalXs));
}
}
|