窃贼问题
窃贼问题是一个典型的最优化问题。窃贼问题的大意如下:
有一个窃贼带着一个背包去偷东西,房屋中共有5件物品,其重量和价值如下:
物品1: 6公斤,48元
物品2: 5公斤,40元
物品3: 2公斤,12元
物品4: 1公斤,8元
物品5: 1公斤,7元。
窃贼希望能够拿最大价值的东西,而窃贼的背包最多可装重量为8公斤的物品。那么窃贼应该装上述哪些物品才能达到要求呢?
1. 窃贼问题算法
首先来分析一下窃贼问题。窃贼问题是关于最优化的问题,可使用动态规划的思想来解最优化问题。窃贼问题求解的操作过程如下:
(1)首先创建一个空集合。
(2)然后向空集合中增加元素,每增加一个元素就先求出该阶段最优解。
(3)继续添加元素,直到所有的元素都添加到集合中,最后得到的就是最优解。
采用上述思路,窃贼问题的求解算法如下:
(1)首先,窃贼将物品i试着添加到方案中。
(2)然后判断是否超重,若未超重,则继续添加下一个物品,重复第一步。
(3)若超重,则将该物品排除在方案之外,并判断此时所有未排除物品的价值是否小于已有最大值;如果满足,则不必再尝试后续物品了。
可以按照此思路来编写相应的窃贼问题的求解算法,代码示例如下:
static class GType{ //物品数据结构 double value; //价值 double weight; //重量 char isSelect; //是否选中到方案 } static double maxvalue; //方案最大价值 static double totalvalue; //物品总价值 static double maxwt; //窃贼能拿的最大重量 static int num; //物品数量 static char[] seltemp; //临时数组 /** * 算法 * @param goods 物品 * @param i 下一个待选物品 * @param wt 盗贼现拿物品重量 * @param vt 可选物品总价值 */ static void backpack(GType[] goods,int i,double wt,double vt){ int k; if(wt+goods[i].weight<=maxwt){ //将物品i包含在当前方案,判断重量小于等于限制重量 seltemp[i]=1; //选中第i个物品 if(i<num-1){ //如果物品i不是最后一个物品 backpack(goods,i+1,wt+goods[i].weight,vt); //递归调用,继续添加物品 }else{ for(k=0;k<num;++k){ goods[k].isSelect=seltemp[k]; } maxvalue=vt; //保存当前方案的最大价值 } } seltemp[i]=0; //取消物品i的选择状态 if(vt-goods[i].value>maxvalue){ //还可以继续添加物品 if(i<num-1){ backpack(goods,i+1,wt,vt-goods[i].value); //递归调用 }else{ for(k=0;k<num;++k){ goods[k].isSelect=seltemp[k]; } maxvalue=vt-goods[i].value; } } }
2. 窃贼问题求解
求解窃贼问题的完整代码如下:
package com.cn.suanfaquti; import java.util.Scanner; public class QieZeiQuestion { static class GType{ //物品数据结构 double value; //价值 double weight; //重量 char isSelect; //是否选中到方案 } static double maxvalue; //方案最大价值 static double totalvalue; //物品总价值 static double maxwt; //窃贼能拿的最大重量 static int num; //物品数量 static char[] seltemp; //临时数组 /** * 算法 * @param goods 物品 * @param i 下一个待选物品 * @param wt 盗贼现拿物品重量 * @param vt 可选物品总价值 */ static void backpack(GType[] goods,int i,double wt,double vt){ int k; if(wt+goods[i].weight<=maxwt){ //将物品i包含在当前方案,判断重量小于等于限制重量 seltemp[i]=1; //选中第i个物品 if(i<num-1){ //如果物品i不是最后一个物品 backpack(goods,i+1,wt+goods[i].weight,vt); //递归调用,继续添加物品 }else{ for(k=0;k<num;++k){ goods[k].isSelect=seltemp[k]; } maxvalue=vt; //保存当前方案的最大价值 } } seltemp[i]=0; //取消物品i的选择状态 if(vt-goods[i].value>maxvalue){ //还可以继续添加物品 if(i<num-1){ backpack(goods,i+1,wt,vt-goods[i].value); //递归调用 }else{ for(k=0;k<num;++k){ goods[k].isSelect=seltemp[k]; } maxvalue=vt-goods[i].value; } } } public static void main(String[] args) { double sumweight; int i; System.out.println("窃贼问题求解!"); System.out.print("窃贼背包能容纳的最大重量:"); Scanner input = new Scanner(System.in); maxwt=input.nextDouble(); //窃贼背包能容纳的最大重量 System.out.print("可选物品数量:"); num = input.nextInt(); //可选物品的数量 GType[] goods=new GType[num]; seltemp = new char[num]; totalvalue=0; //初始化总价值 for(i=0;i<num;i++){ GType t = new GType(); System.out.print("输入第"+(i+1)+"号物品的重量和价值:"); t.weight=input.nextDouble(); t.value = input.nextDouble(); totalvalue+=t.value; goods[i]=t; } System.out.print("\n背包最大能装的重量为:"+maxwt+"\n\n"); for(i=0;i<num;i++){ System.out.println("第"+(i+1)+"号物品重:"+goods[i].weight+",价值:"+goods[i].value); seltemp[i]=0; } maxvalue=0; backpack(goods,0,0.0,totalvalue); //求解 sumweight=0; System.out.println("\n可将以下物品装入背包,使背包的物品价值最大:"); for(i=0;i<num;++i){ if(goods[i].isSelect==1){ System.out.println("第"+(i+1)+"号物品,重量:"+goods[i].weight+",价值:"+goods[i].value); sumweight+=goods[i].weight; } } System.out.println("\n总重量为:"+sumweight+",总价值为:"+maxvalue); } }
程序运行结果如下:
窃贼问题求解! 窃贼背包能容纳的最大重量:8 可选物品数量:5 输入第1号物品的重量和价值:6 48 输入第2号物品的重量和价值:5 40 输入第3号物品的重量和价值:2 12 输入第4号物品的重量和价值:1 8 输入第5号物品的重量和价值:1 7 背包最大能装的重量为:8.0 第1号物品重:6.0,价值:48.0 第2号物品重:5.0,价值:40.0 第3号物品重:2.0,价值:12.0 第4号物品重:1.0,价值:8.0 第5号物品重:1.0,价值:7.0 可将以下物品装入背包,使背包的物品价值最大: 第1号物品,重量:6.0,价值:48.0 第4号物品,重量:1.0,价值:8.0 第5号物品,重量:1.0,价值:7.0 总重量为:8.0,总价值为:63.0