需要的同学请自取哦~欢迎大家与我交流
问题:
0-1背包问题的问题提出是,有n个物品,其中物品i的重量是 ,价值是 ,有一容量为C的背包,要求选择若干物品装入背包,使装入背包的物品总价值达到最大。0-1背包问题中,物品i在考虑是否装入背包时只有两种选择,即要么全部装入背包,要么全部不装入背包,不能只装入物品i的一部分,也不能将物品i装入背包多次。此问题的形式化描述是:给定 ,要求找出n元0-1向量 , , ,使得目标函数 达到最大,且要满足约束条件 。设 ,使用优先队列式分支限界法求解此问题。
package _优先队列式分支限界法_0_1背包;
//子集树结点类描述
class BBnode
{ BBnode parent; // 父结点
boolean leftChild; // 左儿子结点标志
BBnode(BBnode par,boolean ch)
{parent=par;
leftChild=ch;
}
}
/*
//依单位重量价值排序的物品数组类
class Element{
int i;
double id;
public Element(int i,double b) {
this.i=i;
this.id=b;
}
public int compareTo(Element element) {
if(this.id
else if(this.id>element.id)
return 1;
return 0;
}
}
/*
//筛选法调整堆
//将以low为根结点的子树调整成小顶堆,low和high分别是待调整序列的上界和下界
static void sift(int low,int high) {
int i=low;//子树的根结点
int j=2i+1;//j为i结点的左孩子
HeapNode temp=h[i];
while(j
}
if(temp.upperProfit
i=j;
j=2
}else {
j=high+1;//退出循环
}
}
h[i]=temp;//当前子树的原根值调整后的位置
}
//创建堆算法
static void insertheapSort() {
int n=rear-front;//待加入堆的结点个数
HeapNode temp;
for(int i=n/2-1;i>=front;i–) {//创建堆
sift(i,n);
}
}
//取出堆顶元素,并且重新调整堆为最大堆的算法
static HeapNode removeheapSort() {
int n=rear-front;//
int i=n-1;//堆的最后一个结点
HeapNode temp=h[front];
h[front]=h[i];//将堆中最大关键字值移到最前面
sift(front,i);//并且调整成堆
return temp;//返回最顶堆结点
}
//将堆元素node加入堆,并且调整堆
public void insert(HeapNode node) {
h[rear]=node;
rear+=1;//修改尾指针
insertheapSort();//调整堆
}
public HeapNode removemax() {
HeapNode temp=removeheapSort();
rear-=1;
return temp;
}
}
public class BBknapsack {
static double c; // 背包容量
static int n; // 物品总数
static double [ ]w; // 物品重量数组
static double [ ]p; // 物品价值数组
static double cw; // 当前重量
static double cp; // 当前价值
static int [ ] bestx; // 最优解
static MaxHeap heap; // 活结点优先队列
static Element []q;//定义依单位重量价值排序的物品数组
//从该方法可以看出该解法只是构建部分解空间树
将一个新产生的BBNode类型活结点加入到子集树中,并将这个新结点插入到表示活结点优先队列的最大堆中
public static void addLiveNode(double up, double pp, double ww, int lev, BBnode par, boolean ch) {
// TODO Auto-generated method stub
BBnode a=new BBnode(par,ch);//将一个新节点插入子集数
HeapNode node=new HeapNode(a,up,pp,ww,lev);
heap.insert(node);//将结点加入最大堆
}
//在解0-1背包问题的优先队列式界限分支法中,活结点优先队列中结点元素优先级由该结点的上界函数bound计算出的值给出。
private static double bound(int i)
{ double cleft=c-cw; //剩余容量
double b=cp; //价值上界
//以物品单位重量价值递减序装填剩余容量
while(i<=n && w[i]<=cleft)
{ cleft-=w[i];
b+=p[i];
i++;
}
//装填剩余容量装满背包
if(i<=n)b+=p[i]/w[i]*cleft;
return b;
}
//完成对输入数据的预处理
public static double knapsack(double[] pp,double []ww,double cc,int []xx)
{ //返回最大价值,bestx返回最优解
c=cc;
//依单位重量价值排序的物品数组
q=new Element[n];
double ws=0.0; //装包物品重量
double ps=0.0; //装包物品价值
for(int i=1;i<=n;i++)
{
q[i-1]=new Element(i,pp[i]/ww[i]);
ps+=pp[i];
ws+=ww[i];
}
if(ws<=c)//所有物品装包
{
for(int i=1;i<=n;i++)
xx[i]=1;
return ps;
}
//依单位重量价值升序排序
mergeSort(q,0,n-1);
// 初始化类数据成员
p=new double[n+1];
w=new double[n+1];
for(int i=1;i<=n;i++) //转换为降序
{
p[i]=pp[q[n-i].i];
w[i]=ww[q[n-i].i];
}
cw=0.0;
cp=0.0;
bestx=new int[n+1];
HeapNode [ ]h1=new HeapNode[n+1];
heap=new MaxHeap(h1,0,n);
//调用 bbKnapsack 求问题的最优解
double maxp=bbKnapsack();
for(int i=1;i<=n;i++)
xx[q[n-i].i]=bestx[i];//最优解
return maxp;
}
//排序 用于将物品数组依单位重量价值排序
private static void mergeSort(Element[] a, int left, int right) {
Element []b =new Element[right+1];
if(left
mergeSort(a,left,i);//处理左半段
mergeSort(a,i+1,right);//处理右半段
Merge(a,b,left,i,right);//将两段序列合并成有序结果
Copy(a,b,left,right);//复制
}
}
//合并排序,把两段待排序序列合并成有序结果
static void Merge(Element [ ] c, Element d[ ] ,int l, int m , int r) {
int i=l;//第一段的游标(起始位置)
int j=m+1;//第二段的游标(起始位置)
int k=l;//结果的游标
//只要段里面存在i和j,不断进行归并
while((i<=m)&&(j<=r)) {
if(c[i].compareTo(c[j])<=0)
d[k++]=c[i++];
else d[k++]=c[j++];
}
//把余下部分加入到数组中
if(i>m) {
for(int q=j;q<=r;q++)
d[k++]=c[q];
}
else {
for(int q=i;q<=m;q++)
d[k++]=c[q];
}
}
//复制数组
static void Copy(Element[] a, Element[] b, int left, int right) {
for(int i=left;i<=right;i++) {
a[i]=b[i];
}
}
private static double bbKnapsack()
{ //优先队列分支界限法,返回最大价值,bestx 返回最优值
//初始化
BBnode A=null;
BBnode enode=A;
int i=1;
double bestp=0.0; //当前最优值
double up=bound(1); //价值上界
while(i!=n+1) //搜索子集空间树
{//非叶结点
//检查当前扩展结点的左儿子结点
double wt=cw+w[i];
if(wt<=c)
{//左儿子结点为可行结点
if(cp+p[i]>bestp)
bestp=cp+p[i];
addLiveNode(up,cp+p[i],cw+w[i],i+1,enode,true);
}
up=bound(i+1);
//检查当前扩展结点的右儿子结点
if(up>=bestp)
//右子树可能含最优解
addLiveNode(up,cp,cw,i+1,enode,false);
//取下一扩展结点
HeapNode node=(HeapNode)heap.removemax();
enode=node.liveNode;
cw=node.weight;
cp=node.profit;
up=node.upperProfit;
i=node.level; }
//构造当前最优解
for(int j=n;j>0;j–)
{ bestx[j]=(enode.leftChild)?1:0;
enode=enode.parent; }
return cp; }
/*
* 0,16,15,15
* 0,45,25,25
*
* 0,14,7,15,9,20
* 0,6 ,6,8 ,15,18
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
double []ww= { 0,14,7,15,9,20};//物品重量
n=5;//物品总量
double []pp= {0,6 ,6,8 ,15,18};//物品价值
double cc=40;
int[]xx= {0,0,0,0,0,0};
double result= knapsack(pp,ww,cc,xx);
System.out.println("背包最优价值总和为:");
System.out.println(result);//背包最优价值和
System.out.println("对应的最优解为:");
for(int i=1;i<=n;i++) {
System.out.print(xx[i]+" ");//解
}
}
}