背包问题
背包问题(Knapsack problem)是一种组合优化的NP完全问题。问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。也可以将背包问题描述为决定性问题,即在总重量不超过W的前提下,总价值是否能达到V?了解回溯算法
数组的所有子集
/**
* 目标数组的所有子集
* @param array 数组对象
* @return 返回数组子集的集合对象
*/
public List<List<Integer>> subsets(Integer[] array){
// 创建存储子集的集合对象
List<List<Integer>> list = new ArrayList<List<Integer>>();
// 对数组进行排序
Arrays.sort(array);
// 调用回溯函数
backStrack(list,new ArrayList<Integer>(),array,0);
// 返回所有子集结果
return list;
}
回溯算法求子集
/**
* 回溯算法获得数组所有子集
* @param list
* @param arrayList
* @param array
* @param start
*/
private void backStrack(List<List<Integer>> list, List<Integer> arrayList, Integer[] array,int start) {
// 将集合存储到执行集合中 public ArrayList(Collection<? extends E> c)
list.add(new ArrayList<>(arrayList));
// for循环添加
for(int i = start; i < array.length ; i++){
if(!arrayList.contains(array[i])){
// 如果不存在就添加到集合中
arrayList.add(array[i]);
// 元素不可能一次性添加完,所以需要递归
backStrack(list,arrayList,array,i+1);
// 撤销选择,即就是撤销当前list中值,因为在前面已经将arrayList的值传走了
arrayList.remove(arrayList.size()-1);
}
}
}
main测试
public static void main(String[] args) {
// Weigh表示背包能承受的最大重量,maxKey表示最大价值,minWight表示每个子集的重量,temp临时变量,wight存储最大价值对应的重量
Integer Weigh = 0,maxKey = 0,minWight = 0,temp = 0,wight = 0;
// 存储最终的子集
List<Integer> result = null;
// map中键存储的是索引值,值存储的是重量
Map<Integer,Integer> key = new HashMap<Integer,Integer>();
// 创建键盘输入流
Scanner input = new Scanner(System.in);
System.out.println("背包的最大容量:");
Weigh = input.nextInt();
System.out.println("物品个数:");
int index = input.nextInt();
// map中索引值对应此处的价值
Integer[] value = new Integer[index];
for(int i = 0 ; i < index ; i++){
System.out.print("物品"+(i+1)+"质量:");
key.put(i,input.nextInt());
System.out.print("物品"+(i+1)+"价值:");
value[i] = input.nextInt();
}
Knapsack kp = new Knapsack();
Integer[] array = key.keySet().toArray(new Integer[0]);
List<List<Integer>> list = kp.subsets(array);
for(List<Integer> l : list){
minWight = 0;
// 迭代器遍历map集合并计算其重量是否超过最大重量
Iterator<Integer> iter = l.iterator();
while(iter.hasNext())
// 将该子集的所有重量相加
minWight += key.get(iter.next());
// 如果重量小于等于最大重量则,计算其价值
if(minWight <= Weigh){
// 初始化临时变量
temp = 0;
// 迭代器遍历子集,并通过数组索引计算其价值是否最大
Iterator<Integer> it = l.iterator();
while(it.hasNext())
// 计算重量不超过最大重量子集中某个背包的价值
temp += value[it.next()];
// 如果当前背包的价值大于之前的,那么替换掉
if(temp > maxKey) {
// 记录当前的最大价值
maxKey = temp;
// 记录当前的重量
wight = minWight;
// 记录当前的集合
result = l;
}
}
}
System.out.println("背包:"+result+" 最大价值为:"+maxKey+" 重量为:"+wight);
}
测试案例
案例:
背包的最大容量:
15
物品个数:
5
物品1质量:2
物品1价值:2
物品2质量:12
物品2价值:4
物品3质量:1
物品3价值:2
物品4质量:1
物品4价值:1
物品5质量:4
物品5价值:10
背包:[0, 2, 3, 4] 最大价值为:15 重量为:8