1.分支限定法:
特点:1.每一个节点,都有2种可能 “存在”、“不存在”
2. 每一次的 V/W 取的都是下一个放入节点的 V/W
3.取叶子节点 最大 的值,就是最优解
例如:0-1背包问题,假设有4个物品,其重量分别为 (4,7,5,3),价值分别为(40,42,25,12) 背包容量W= 10,首先,将给定物品按单位价值从大到小排序,结果如下:
物品 | 重量(w) | 价值(v) | 价值/重量(v/w) |
---|---|---|---|
1 | 4 | 40 | 10 |
2 | 7 | 42 | 6 |
3 | 5 | 25 | 5 |
4 | 3 | 12 | 4 |
最终得到 : 9, 7, 3 这三个叶子节点,其中 9 节点的ub 最大 所以也是最优解
流程分析:
节点1: 不放入第一个物品,W = 0 V=0, ub = 100
节点2: 放入 第一个物品,W = 4, v = 0, ub = 76
节点 3:不放入 第二个物品,W = 0, V=0 ub = 60
节点4 :放入 第二个物品,重量超出!
节点5: 不放入 第三个物品,此时背包中只有第一个物品,W = 4 v = 40
ub 70 = 40 + (10- 4[节点1 的重量 ] = 6 ) x 5 [节点3的v/w]
节点6 :放入第三个物品 ,W = 4+5 = 9 V = 40+25 = 65
ub 69 = 65 + (10-9 = 1) x 4
节点 7 :不放入 第四个物品, 此时背包中只有第一个物品,W = 4 v = 40
ub 64 = 40 + (10-4 = 6) x 4
节点8 : 放入第四个物品,此时背包中有1,3 两个物品 ,加上第四个物品的重量,W = 12 超出!
节点9 : 不放入第四个物品,背包中有 1,3 两个物品 w = 9, v = 65
ub 65 = 65 + (10-9 =1) x 0
代码实现:
/**
* @Author wuxiaotian
* @Date 2021/8/24 19:30
* @Version C1.4
*/
public class Test02 {
int[] w = new int[] {40,42,25,12}; //每个物品的重量
int[] x = new int[] {0, 0, 0,0}; //x[i]=1代表物品i放入背包,0代表不放入
int CurValue = 0; //当前放入背包的物品总重量
int BestValue = 0; //最优值;当前的最大价值,初始化为0
int[] BestX = new int[4]; //最优解;BestX[i]=1代表物品i放入背包,0代表不放入
int N = BestX.length; // 容量
int C = 100; // 期望值
//t = 0 to N-1
void backtrack(int t) {
//叶子节点,输出结果
if (t > N - 1) {
//如果找到了一个更优的解
if (CurValue > BestValue) {
//保存更优的值和解
BestValue = CurValue;
for (int i = 0; i < N; ++i) {
BestX[i] = x[i];
}
}
} else {
//遍历当前节点的子节点:0 不放入背包,1放入背包
for (int i = 0; i <= 1; ++i) {
x[t] = i;
//不放入背包
if (i == 0) {
backtrack(t + 1);
}
//放入背包
else {
//约束条件:放的下
if ((CurValue + w[t]) <= C) {
CurValue += w[t];
backtrack(t + 1);
CurValue -= w[t];
}
}
}
}
}
public static void main(String[] args) {
Test02 test2 = new Test02();
test2.backtrack(0);
for (int i = 0; i < 4; i++) {
System.out.println(test2.BestX[i]);
}
}
}