* (3)算法详细描述:
* (3.1)先让用户输入要测试数据的编号
* (3.2)从文件中读取背包的体积,物品的价值和体积,并对物品进行封装,最后存储在list中。
* (3.3)初始化一个二维数组用于存放求解过程中的结果
* (3.4)调用solve函数进行求解:
* 对于背包体积为0的情况和物品个数为前0个的情况,价值都为0,作为初始
* 考虑要选择放入的第k个物品的体积是否大于当前背包的体积:
* 若小于,则不放入背包,此时的价值等于前(k-1)个物品在当前背包体积的最大价值
* 若大于等于,则考虑要不要放进去:
* 若放进去,此时背包的价值等于:放入第k个之后,前(k-1)个物品在背包剩余体积中的最大价值与第k个物品价值之和(这里的放进去指的是先把第k个物品放进去,然后根据剩余的体积在之前的表中找能装前(k-1)件物品实现的最大价值。而不是在已经装了(k-1)件的最大价值基础上再装k)
* 若不放进去,此时的价值等于前(k-1)个物品在当前背包体积的最大价值
* 比较以上两种结果,将较大的数作为前k件物品在当前背包容量的最大价值
* (5)打印出求解过程的结果矩阵
* (6)逆向求解放入背包中的物品编号:如果第k件物品在当前背包容量实现的最大价值等于前(k-1)件物品实现的最大价值,则第k件物品没有被 放入;如果大于,则被放入
/**
* 物品实体类
*/
public class Item {
private int number;//物品编号
private int value;//物品价值
private int weight;//物品重量
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
@Override
public String toString() {
return "Item{" +
"number=" + number +
", value=" + value +
", weight=" + weight +
'}';
}
}
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class KnapsackProblem {
private static int packageV = 0;//背包的体积,初始化为0,需要从文件数据中读取
public static void main(String[] args) throws IOException {
System.out.println("请输入测试数据的编号:");
Scanner input = new Scanner(System.in);
int number = input.nextInt();//用户输入测试数据的编号
List<Item> items = readData(number);//将读取的数据进行封装存储到list中
//创建二维数组保存求解过程中的结果,多一行表示前0个物品,多一列表示背包体积为0时的情况,作为初始情况
int[][] result = new int[items.size()+1][packageV+1];
solve(result,items);//求解前k件物品放入背包的最大价值并保存在二维数组中
printResult(result);//打印出结果矩阵
findItem(result,items);//根据结果逆向求解出放入物品的编号
}
/**
* 读取数据
* @param number:测试数据的编号
* @return :封装好的物品信息list
* @throws IOException
*/
public static List<Item> readData(int number) throws IOException {
List<Item> items = new ArrayList<>();
BufferedReader reader = new BufferedReader(
new FileReader(".\\input_assign02_0"+number+".dat"));
String info = reader.readLine();
packageV = Integer.valueOf(info.split(" ")[0]);
String line = null;
int weight = 0;
int value = 0;
int num = 0;
//按行读取,使用空格对字符串进行分割
while ((line = reader.readLine())!=null){
num = Integer.valueOf(line.split(" ")[0]);
weight = Integer.valueOf(line.split(" ")[1]);
value = Integer.valueOf(line.split(" ")[2]);
Item item = new Item();
item.setNumber(num);
item.setValue(value);
item.setWeight(weight);
items.add(item);
}
reader.close();
return items;
}
/**
* 打印求解过程的结果矩阵
* @param arr :存储求解过程的结果
*/
public static void printResult(int[][] arr){
System.out.print("背包体积 ");
//打印背包求解过程时的体积
for(int i=0;i<=packageV;i++){
System.out.print(i+"\t");
}
System.out.println();
System.out.println("\t编号");
for(int i=0;i< arr.length;i++){
//表示前i个物品作为第一列
System.out.print("\t"+i+"\t");
for(int j=0;j<arr[i].length;j++){
//打印不同情况下的结果
System.out.print(arr[i][j]+"\t");
}
System.out.println();
}
}
/**
* 求解背包问题的过程
* @param arr :用于存储求解过程的数组
* @param items :物品列表
* @return :存储好求解过程的二维数组
*/
public static int[][] solve(int[][] arr,List<Item> items){
//前0个物品在背包多大的情况下的最大价值都是0
for(int i=0;i<=packageV;i++){
arr[0][i] = 0;
}
//背包体积为0时,任何物品也不能放下,最大价值也为0
for(int i=0;i< arr.length;i++){
arr[i][0] = 0;
}
for(int i=1;i<arr.length;i++){//前i个物品
for(int j=1;j<packageV+1;j++){//背包体积为j时
Item item = items.get(i-1);//第i个物品
if(item.getWeight()>j){//如果物品的体积大于当前背包的体积
arr[i][j] = arr[i-1][j];//第i个物品放不进去,此时的最大价值等于前(k-1)个物品在体积为j时的最大价值
}else{//第i个物品能放的进背包
int remain = j-item.getWeight();//背包除去第i个物品体积后剩余的体积
int putValue = arr[i-1][remain]+item.getValue();//第i个物品放进去的价值等于第i件物品的价值与剩余背包体积下(k-1)件物品能实现的最大价值
int noPutValue = arr[i-1][j];//第i个物品选择不放的价值等于前(k-1)个物品在体积为j时的最大价值
if(putValue>=noPutValue){//比较放与不放的价值,取最大作为当前的最大价值
arr[i][j] = putValue;
}else{
arr[i][j] = noPutValue;
}
}
}
}
System.out.println("此时背包的最大价值为:"+arr[items.size()][packageV]);
return arr;
}
/**
* 找出放入背包的物品编号
* @param arr :存储求解过程的结果矩阵
* @param list :物品列表
* @return :存储背包中物品编号的一维数组
*/
public static int[] findItem(int[][] arr,List<Item> list){
int[] itemNumber =new int[list.size()];//存储背包中物品编号的一维数组
//初始化数组
for(int i=0;i<itemNumber.length;i++){
itemNumber[i] = -1;
}
int index = 0;//记录物品个数
int i = arr.length-1;//从后往前遍结果矩阵的物品
int currentV = packageV;//当前的背包体积
while(i>0){
if(arr[i][currentV]!=arr[i-1][currentV]){//如果前i个物品的价值不等于前(i-1)个的价值,说明第i个物品有放进去;否则就是没有放进去
itemNumber[index++] = list.get(i-1).getNumber();//将该物品的编号存入数组
currentV-=list.get(i-1).getWeight();//将体积减去第i件的体积作为当前体积
}
i--;//继续寻找在当前体积下的最大值
}
System.out.print("背包中物品的序号为:");
for(int num:itemNumber){//打印背包中物品的序号
if(num!=-1){
System.out.print(num+"\t");
}
}
return itemNumber;
}
}
标签:arr,背包,int,问题,体积,物品,public 来源: https://blog.csdn.net/qq_42525835/article/details/120945794
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。