本文由此博客更改而来,对此博客的解法进行了部分修改,代码结构尚有很多不足之处,敬请原谅~
具体实现请看代码及其注释:
定义的一个节点对象,封装v与w等信息,将被作为二叉树节点使用
class ItemNode implements Comparable<ItemNode>{
int weight;//该节点目前背包中的重量
double value;//该节点目前背包中的总价值
double upprofit;//该节点能够达到的价值上界
int selected; //该节点是否属于左节点(用于最终构造最优解)
int level; //该节点是第几个物品的选择
int index;
ItemNode parent; //该节点的父节点
public int compareTo(ItemNode node){
if(this.upprofit<node.upprofit)
return 1;
else if(this.upprofit == node.upprofit)
return 0;
else
return -1;
}
}
定义算法对象
public class AlgorithmFor01Bag {
int n = 5;
int capacity = 10;
int[] weight = { 2, 6, 4, 1, 5 };
double[] value = { 6, 9, 6, 1, 4 };
int maxValue ;
int[] bestWay ;
//存放下标为i的当前的value与weight在原来的数组中的位置
private int[] originalplace;
/** * 将原数组进行按照单位价值进行排序,初始化originalplace */
private void sort(){
ItemNode node;
List<ItemNode> nodesList=new LinkedList<ItemNode>();
for(int i=0;i<n;i++){
node=new ItemNode();
node.index=i
node.value=value[i];
node.weight=weight[i];
nodesList.add(node);
}
Collections.sort(nodesList, new Comparator<ItemNode>() {
@Override
public int compare(ItemNode o1, ItemNode o2) {
if(o1.value/o1.weight > o2.value/o2.weight)
return -1;
else if(o1.value/o1.weight < o2.value/o2.weight)
return 1;
return 0;
}
});
int i = 0;
originalplace = new int[value.length];
for (ItemNode curnode : nodesList) {
originalplace[i] = curnode.index;
value[i] = curnode.value;
weight[i] = curnode.weight;
++i;
}
}
//实际上构建的是一颗子孙节点指向父节点,但是父节点不知道孩纸节点的二叉树,并且不断扩张该二叉树
public void getMaxValue(double[] _value,int[] _weight,int limitopacity){
//为了当前操作不影响外面传进来的数组,复制传进的数组
if(_value!=null&&_weight!=null){
value=new double[_value.length];
System.arraycopy(_value,0,value, 0,_value.length);
weight=new int[_weight.length];
System.arraycopy(_weight,0,weight, 0,_weight.length);
}
bestWay=new int[_value.length];
capacity=limitopacity;
maxValue = -1;
n=_value.length;
sort();
PriorityQueue<ItemNode> pq = new PriorityQueue<ItemNode>();
//构造一个初始化节点,属于-1层
ItemNode initial = new ItemNode();
initial.level = 0; //欺骗写法,为了是重用maxBound函数
initial.weight=0;
initial.value=0;
initial.upprofit=maxBound(initial);
initial.level=-1;
pq.add(initial);
//*************core code begin********
while(!pq.isEmpty()){
ItemNode fatherNode = pq.poll();
// 当前节点是叶子节点,不用扩展,直接退出
if (fatherNode.level == n - 1) {
continue;
}
//试探左节点,做节点的原则是:容量可以容纳就加入该节点,加入改节点
if (weight[fatherNode.level + 1] + fatherNode.weight <= capacity) {
ItemNode leftNode = new ItemNode();
leftNode.level = fatherNode.level + 1;
leftNode.value = fatherNode.value + value[fatherNode.level + 1];
leftNode.weight = weight[fatherNode.level + 1]
+ fatherNode.weight;
leftNode.upprofit = maxBound(leftNode);
leftNode.parent = fatherNode;
leftNode.selected = 1;
//如果有最大值,记录最大值,可以自定义这个函数
if (leftNode.value > maxValue) {
maxValue = (int) leftNode.value;
ItemNode tracknode = leftNode;
for (int i = leftNode.level; i >= 0; i--) {
bestWay[originalplace[i]] = tracknode.selected;
tracknode = tracknode.parent;// 往前遍历,到达上一层节点
}
for (int i = leftNode.level + 1; i < n; i++) {
bestWay[originalplace[i]] = 0;
}
}
if (leftNode.upprofit > maxValue) {
pq.add(leftNode);
}
}
//试探右结点,右节点的原则是:不加入当前的节点,无论是否能够容纳
ItemNode rightNode = new ItemNode();
rightNode.level = fatherNode.level + 1;
rightNode.value = fatherNode.value;
rightNode.weight = fatherNode.weight;
rightNode.upprofit=maxBound(rightNode);
if (rightNode.upprofit > maxValue) {
rightNode.parent = fatherNode;
rightNode.selected = 0; // 表示当前节点不加入背包
pq.add(rightNode);
}
}
//*************core code end********
}
// 用于计算该节点的最高的贪心价值上界
public double maxBound(ItemNode no) {
double maxLeft = no.value;
int leftWeight = capacity - no.weight;
int templevel = no.level+1;
// 尽力依照单位重量价值次序装剩余的物品
while (templevel <= n - 1 && leftWeight > weight[templevel]) {
leftWeight -= weight[templevel];
maxLeft += value[templevel];
templevel++;
}
// 不能装时,用下一个物品的单位重量价值折算到剩余空间。
if (templevel <= n - 1) {
maxLeft += value[templevel] / weight[templevel] * leftWeight;
}
return maxLeft;
}
}
测试用例:
public static void main(String[] args) {
AlgorithmFor01Bag b = new AlgorithmFor01Bag();
// int[] weight = { 2, 6, 4, 1, 5 };
// double[] value = { 6, 9, 6, 1, 4 };
int[] weight = { 2, 6, 4, 5, 1};
double[] value = { 6, 9, 6, 4, 1 };
b.getMaxValue(value, weight, 10);
System.out.println("该背包能够取到的最大价值为:" + b.maxValue);
System.out.println("取出的方法为:");
for (int i : b.bestWay)
System.out.print(i + " ");
}
该背包能够取到的最大价值为:16
取出的方法为:
1 1 0 0 1