分支限界——01背包问题

xiaoxiao2021-02-28  113

回溯法采用的是深度优先搜索,而分支限界采用的则是广度优先搜索。

  分支限界法的搜索策略是,在扩展结点处,先生成其所有的儿子结点(分支),然后再从当前的活结点表中选择下一扩展结点。为了有效地选择下一扩展结点,加速搜索的进程,在每一个活结点处,计算一个函数值(限界),并根据函数值,从当前活结点表中选择一个最有利的结点作为扩展结点,使搜索朝着解空间上有最优解的分支推进,以便尽快地找出一个最优解

常见的有两种分支限界的方法:1.队列式分支限界法      2.优先队列式分支限界法

这里采用优先队列式分支限界法来解决01背包问题。

如背包容量为30,有三个物品质量分别为16,15,15,价值分别为45,25,25。

解空间树为:(盗的图)

代码如下:(Java实现)

import java.util.PriorityQueue; import java.util.Scanner; class PackNode implements Comparable<PackNode>{ int weight;//该节点目前背包中的重量 double value;//该节点目前背包中的总价值 double upValue;//该节点能够达到的价值上界 int Left; //该节点是否属于左节点 int level; //该节点是第几个物品的选择 PackNode father; //该节点的父节点 public int compareTo(PackNode node){ if(this.upValue<node.upValue) return 1; else if(this.upValue== node.upValue) return 0; else return -1; } } public class Knapsack0 { static int W;//箱子容量 static int n;//物品数量 static int []w;//物品重量 static double []v;//物品价值 static int maxValue;//最大的价值 static int[] bestWay;//最佳选择 static void getMaxValue(){ PriorityQueue<PackNode> pq = new PriorityQueue<PackNode>(); //构造一个初始化节点,属于-1层 PackNode initial = new PackNode(); initial.level = -1; for(int i=0;i<v.length;i++) initial.upValue+=v[i]; pq.add(initial); while(!pq.isEmpty()){ PackNode fatherNode = pq.poll(); if(fatherNode.level == n-1){ if(fatherNode.value > maxValue){ maxValue = (int)fatherNode.value; for(int i=n-1;i>=0;i--){ bestWay[i] = fatherNode.Left; fatherNode = fatherNode.father; } } } else{ //先统计其左节点信息,判断是否加入队列。 if(w[fatherNode.level+1]+fatherNode.weight <= W){ PackNode newNode = new PackNode(); newNode.level = fatherNode.level+1; newNode.value = fatherNode.value + v[fatherNode.level+1]; newNode.weight = w[fatherNode.level+1]+fatherNode.weight; newNode.upValue = Bound(newNode); newNode.father = fatherNode; newNode.Left = 1; if(newNode.upValue > maxValue) pq.add(newNode); } //向右节点搜索,其能够取到的价值上界通过父亲节点的上界减去本层物品的价值。 if((fatherNode.upValue - v[fatherNode.level+1])> maxValue){ PackNode newNode2 = new PackNode(); newNode2.level = fatherNode.level+1; newNode2.value = fatherNode.value; newNode2.weight = fatherNode.weight; newNode2.father = fatherNode; newNode2.upValue = fatherNode.upValue - v[fatherNode.level+1]; newNode2.Left = 0; pq.add(newNode2); } } } } //用于计算该节点的最高价值上界 static double Bound(PackNode node){ double maxLeft = node.value; int leftWeight = W - node.weight; int templevel = node.level; //尽力依照单位重量价值次序装剩余的物品 while(templevel <= n-1 && leftWeight > w[templevel] ){ leftWeight -= w[templevel]; maxLeft += v[templevel]; templevel++; } //不能装时,用下一个物品的单位重量价值折算到剩余空间。 if( templevel <= n-1){ maxLeft += v[templevel]/w[templevel]*leftWeight; } return maxLeft; } public static void main(String[] args){ Scanner input=new Scanner(System.in); System.out.println("箱子容量:"); W=input.nextInt(); System.out.println("物品数量:"); n=input.nextInt(); w=new int[n]; v=new double[n]; bestWay=new int[n]; System.out.println("每一件物品的重量:"); for(int i=0;i<n;i++){ w[i]=input.nextInt(); } System.out.println("每一件物品的价值:"); for(int i=0;i<n;i++){ v[i]=input.nextDouble(); } getMaxValue(); System.out.println("该背包能够取到的最大价值为:"+maxValue); System.out.println("所取物品:"); for(int i=0;i<bestWay.length;i++){ System.out.print(bestWay[i]+" "); } } }

转载请注明原文地址: https://www.6miu.com/read-20172.html

最新回复(0)