经典例题
0-1背包问题
问题定义【来自百度百科】
我们有n种物品,物品j的重量为wj,价格为pj。
我们假定所有物品的重量和价格都是非负的。背包所能承受的最大重量为c。
如果限定每种物品只能选择0个或1个,则问题称为0-1背包问题
实例描述
对于n=3的0-1背包问题, 物品的重量为w={16, 15, 15}, 物品的价值为p={45, 25, 25},背包承重最大值:C=30,求背包中能够装载的最大价值。
-
定义问题解空间;
result=({0,0,0},{0,0,1},{0,1,0},{0,1,1},{1,0,0},{1,0,1},{1,1,0},{1,1,1}),共8种结果 -
确定易于搜索的解空间结构;
该问题的解空间结构为子集树
A代表第一件物品,0表示不把物品装进背包,1表示把物品装进背包
子集树概念:
当所给的问题是从包含n个元素的集合S中找出能满足某种性质的子集时,相应的解空间树称为子集树。例如,0-1背包问题的解空间树就是一棵子集树。这类子集树通常有2n个叶结点。遍历子集树的任何算法均需O(2的n次方)的计算时间。
子集树代码框架如下:
void backtrack (int t)
{ if (t>n) output(x);
else
for (int i=0;i<=1;i++) {
x[t]=i;
if (legal(t)) backtrack(t+1);
}
}
- 以深度优先方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索。
该问题的限界函数为
代码实现
代码参考该博主,点击进入原博主博文,原博主写的很好!
以下仅做了在输出方面的修改
package KnapsackProblem;
public class _01KnapsackProblem {
public int[] weight;
public int[] value;
public int[] take;
int curWeight = 0;
int curValue = 0;
int bestValue = 0;
int[] bestChoice;
int count;
int maxWeight = 0;
public void init(int[] weight, int[] value, int maxWeight) {
if (weight == null || weight.length == 0
|| value == null || value.length == 0
|| weight.length != value.length || maxWeight <= 0) {
System.out.println("args wrong!");
return;
}
this.value = value;
this.weight = weight;
this.maxWeight = maxWeight;
count = value.length;
take = new int[count];
bestChoice = new int[count];
}
public int[] maxValue(int x) {
//走到了叶子节点
if (x > count - 1) {
//更新最优解
if (curValue > bestValue) {
bestValue = curValue;
for (int i = 0; i < take.length; i++) {
bestChoice[i] = take[i];
}
}
} else {
//遍历当前节点(物品)的子节点:0 不放入背包 1:放入背包
for (int i = 0; i < 2; i++) {
take[x] = i;
if (i == 0) {
//不放入背包,接着往下走
maxValue(x + 1);
} else {
//约束条件,如果小于背包容量
if (curWeight + weight[x] <= maxWeight) {
//更新当前重量和价值
curWeight += weight[x];
curValue += value[x];
//继续向下深入
maxValue(x + 1);
//回溯法重要步骤,个人感觉也是精华所在。
// 当从上一行代码maxValue出来后,需要回溯容量和值
curWeight -= weight[x];
curValue -= value[x];
}
}
}
}
return bestChoice;
}
public static void main(String[] args) {
_01KnapsackProblem bt=new _01KnapsackProblem();
bt.init(new int[]{16,15,15},new int[]{45,25,25},30);
int[] result = bt.maxValue(0);
System.out.print("最佳选择为:[");
for(int i=0;i<bt.bestChoice.length;i++) {
if(i==bt.bestChoice.length-1) {
System.out.print(bt.bestChoice[i]+"]");
}else {
System.out.print(bt.bestChoice[i]+",");
}
}
System.out.print("\n此时价值最大,即"+bt.bestValue);
}
}