问题描述:
给定n种物品和一背包。物品i的重量是wi>0,其价值为vi>0,背包的容量为c。问应如何选择装入背包中的物品,使得装入背包中物品的总价值最大?
源代码:
public class 回溯法01背包{
private static int[] p;//物品的价值数组
private static int[] w;//物品的重量数组
private static int c;//最大可以拿的重量
private static int count;//物品的个数
private static int cw;//当前的重量
private static int cp;//当前的价值
static int bestp;//目前最优装载的价值
private static int[] cx;//存放当前解
private static int[] bestx;//存放最终解
public static int Loading(int[] ww,int[] pp, int cc) {
//初始化数据成员,数组下标从1开始
count = ww.length - 1;
w = ww;
p = pp;
c = cc;
cw = 0;
bestp = 0;
cx = new int[count+1];
bestx = new int[count+1];
//调用回溯法计算
BackTrack(1);
return bestp;
}
//BackTrack函数
public static void BackTrack(int t) {
if(t>count) {//到达叶结点
if(cp>bestp) {//若当前解值>最优解值
//将当前解数组记录在最优解数组中
for(int i = 1;i<=count;i++)
bestx[i] = cx[i];
bestp = cp;//同时更新最优解值
}
return;
}
if(cw + w[t] <= c) {//搜索左子树,判断是否可放入
cx[t] = 1;//放入
cp += p[t];//同步更新当前背包的总价值
cw += w[t];//同步更新当前背包的重量
BackTrack(t+1);//深度搜索进入下一层
cp -= p[t];//回溯复原
cw -= w[t];//回溯复原
cx[t] = 0;//拿出
}
if(bound(t+1)>bestp)//如若符合条件则搜索右子树
BackTrack(t+1);
}
//计算上界函数,功能为剪枝
static double bound(int i){ //判断当前背包的总价值cp+剩余容量可容纳的最大价值<=当前最优价值
double leftw= c-cw;//剩余背包容量
double b = cp;//记录当前背包的总价值cp,最后求上界
//以物品单位重量价值递减次序装入物品
while(i<=count && w[i]<=leftw)
{
leftw-=w[i];
b+=w[i];
i++;
}
//装满背包
if(i<=count)
b+=w[i]/w[i]*leftw;
return b;//返回计算出的上界
}
//将物品按单价升序的方法
public static void sort(int w1[],int p1[]) {
for(int i=1;i<w1.length;i++)
for(int j=i;j<w1.length;j++) {
if( (double)(p1[j])/w1[j]>(double)(p1[i])/w1[i] ) {
int tempw,tempp;
tempw=w1[i];
w1[i]=w1[j];
w1[j]=tempw;
tempp=p1[i];
p1[i]=p1[j];
p1[j]=tempp;
}
}
}
//展示物品重量价值的方法
public static void show(int w[],int p[]) {
for(int i=1;i<w.length;i++)
System.out.println((i)+"号物件质量:"+w[i]+" 价值:"+p[i]);
}
//打印bestx(最优)方案
public static void showresult(int bestx[]) {
System.out.print("放入物品编号为:");
for(int i=1;i<bestx.length;i++)
if(bestx[i]==1)
System.out.print( i +"号 ");
}
//主函数用于测试
public static void main(String[] args) {
//物品重量数组
int[] w1 = {0,15,25,40,20,15,24,28};
//物品价值数组
int[] p1 = {0,10,5 ,20,2 ,14,23,10};
int c1 = 30;//最大容量
System.out.println("物品信息为:");
show(w1,p1);//展示物品信息
System.out.println("排序后物品信息为:");
sort(w1,p1); //将物品按单价排序
show(w1,p1);//展示排序后物品信息
//执行
Loading(w1,p1,c1);
//显示结果
showresult(bestx);
System.out.println("最优装载为:" + bestp);
}
}