1 问题描述
给定n个重量为w1,w2,w3,…,wn,价值为v1,v2,…,vn的物品和一个承重为W的背包,求这些物品中最有价值的子集(PS:每一个物品要么选一次,要么不选),并且要能够装到背包。
附形象描述:就像一个小偷打算把最有价值的赃物装入他的背包一样,但如果大家不喜欢扮演小偷的角色,也可以想象为一架运输机打算把最有价值的物品运输到外地,同时这些物品的重量不能超出它的运输能力。
2 解决方案
2.1 蛮力法
使用蛮力法解决包含n个物品的背包问题,首先得求出这n个物品的所有子集,对于每一个物品存在两种情况:选中(在程序中用1表示),未选中(在程序中用0表示)。该n个物品的所有子集数数量为2^n。下面请看一个简单示例:
package com.liuzhen.chapterThree;
public class Knapsack {
public int maxSumValue = 0; //定义满足背包问题子集的最大承重所得的总价值,初始化为0
/*
* 数组A的行数为2^n,代表n个物品共有2^n个子集,列数为n。即每一行的排列为一个背包实例
* 数组weight存放每个物品的具体重量
* 数组value存放每个物品的具体价值
* n代表共有n个物品
* maxWeight表示背包最大承重量
*/
public void bruteForce(int[][] A,int[] weight,int[] value,int n,int maxWeight){
for(int i = 0;i < Math.pow(2, n);i++){ //总共有2^n个子集,需要进行2^n次循环,及数组A有2^n行
int temp1 = i;
for(int j = 0;j < n;j++){ //数组A有n列,每一列代表一个物品
int temp2 = temp1%2;
A[i][j] = temp2;
temp1 = temp1/2;
}
}
printArray(A,weight,value,maxWeight);
}
//输出穷举方案的背包实例的选择物品(0代表不包含该物品,1表示包含该物品)的总重量及总价值,并输出最优实例的总价值
public void printArray(int[][] A,int[] weight,int[] value,int maxWeight){
int len1 = A.length; //二维数组的行数
int len2 = A[0].length; //二维数组的列数
for(int i = 0;i < len1;i++){
int tempWeight = 0; //暂时计算当前选中背包实例物品的总重量,初始化为0
int tempSumValue = 0; //暂时计算当前选中背包实例物品的总价值,初始化为0
for(int j = 0;j < len2;j++){
System.out.print(A[i][j]+" ");
// if(A[i][j] != 0)
// System.out.print(" 物品"+j);
tempWeight += A[i][j]*w