0-1背包问题
2013-07-15 22:42
239 查看
回溯法:适用于背包容量C远大于物品个数N,时间复杂度O(2*N )
分支限界算法:采用优先队列对子集树进行搜索。对于某个结点,上界 = 剩余背包容量的完全背包最优解 + 当前收益。算法不断扩展结点,直至子集树的叶结点成为扩展结点为止。此时,该叶结点相应的解为最优解,优先队列所有活结点的上界值均不超过该叶结点的价值收益(对于该结点,收益上界 = 当前收益)。
动态规划:由于大多数情况下,部分子问题不用求解,故适合采用备忘录方法
DP算法:对于物品重量较小,且背包容量C=O(N)时,适合采用传统的自底向上的DP算法(时间复杂度为O(CN))。但此场景比较少见,故未给出该算法
import java.util.Arrays; import java.util.Scanner; public class Knapsack { private Bag[] bags; private int capacity; private int[] x; private int maxValue; private int currentValue; private int currentWeight; int count = 0; public Knapsack(Bag[] bags, int capacity){ this.bags = bags; this.capacity = capacity; this.x = new int[bags.length]; this.maxValue = 0; this.currentValue = 0; this.currentWeight = 0; } public int getMaxValue(){ //sort the bag in decrease order by value/weight Arrays.sort(bags); getMaxValue(0); return this.maxValue; } private void getMaxValue(int level){ count ++; //find a answer if(level >= bags.length){ if(currentValue > maxValue) maxValue = currentValue; return; } //choose the current bag if(this.currentWeight + bags[level].weight <= this.capacity){ this.x[level] = 1; this.currentValue += bags[level].value; this.currentWeight += bags[level].weight; getMaxValue(level + 1); this.currentValue -= bags[level].value; this.currentWeight -= bags[level].weight; } //check next bag if currentValue + result of full knapsack > bestValue if(bound(level + 1)){ this.x[level] = 0; getMaxValue(level + 1); } } private boolean bound(int level){ float max = this.currentValue; int available = this.capacity - this.currentWeight; //use the result of full knapsack with capacity 'available' as the bound while(level < bags.length && bags[level].weight <= available){ available -= bags[level].weight; max += bags[level].value; level++; } if(level < bags.length){ max += available * bags[level].price; } return max >= this.maxValue; } private static class Bag implements Comparable<Bag>{ int weight; int value; float price; public Bag(int weight, int value) { super(); this.weight = weight; this.value = value; this.price = (float)value / (float)weight; } @Override public int compareTo(Bag other) { if((other.price - this.price) > 0) return 1; else return -1; } } public static void main(String[] args){ Scanner stdIn = new Scanner(System.in); while(stdIn.hasNext()){ int capacity = stdIn.nextInt(); if(capacity <= 0) break; int bagNum = stdIn.nextInt(); Bag[] bags = new Bag[bagNum]; for(int i = 0; i < bagNum; i++){ int weight = stdIn.nextInt(); int value = stdIn.nextInt(); bags[i] = new Bag(weight, value); } Knapsack OJ = new Knapsack(bags, capacity); System.out.println(OJ.getMaxValue()); System.out.println(OJ.count); } } }
分支限界算法:采用优先队列对子集树进行搜索。对于某个结点,上界 = 剩余背包容量的完全背包最优解 + 当前收益。算法不断扩展结点,直至子集树的叶结点成为扩展结点为止。此时,该叶结点相应的解为最优解,优先队列所有活结点的上界值均不超过该叶结点的价值收益(对于该结点,收益上界 = 当前收益)。
public class Knapsack { private Bag[] bags; private int capacity; private int maxValue; //current expand node private Node current; private PriorityQueue<Node> queue; private boolean[] bestX; public Knapsack(Bag[] bags, int capacity){ this.bags = bags; this.capacity = capacity; this.maxValue = 0; this.bestX = new boolean[this.bags.length + 1]; this.queue = new PriorityQueue<Node>(); } public int getMaxValue(){ int level = 0; Arrays.sort(bags); this.current = new Node(0, 0, 0, bound(0), false, null); while(level != bags.length){ //try to choose the bags[level] if(current.currentWeight + bags[level].weight <= this.capacity){ if(current.currentValue + bags[level].value > maxValue){ maxValue = current.currentValue + bags[level].value; } queue.add(new Node(level + 1, current.currentValue + bags[level].value, current.currentWeight + bags[level].weight, current.upBound, true, current)); } //try to discard the bags[level] float upBound = bound(level + 1); if( upBound >= maxValue){ queue.add(new Node(level + 1, current.currentValue, current.currentWeight, upBound, false, current)); } current = queue.poll(); level = current.level; } return current.currentValue; } public void showSolution(){ calSolution(); for(int i = 1; i < bags.length; i++){ if(bestX[i]) System.out.printf("%d ", i); } if(bestX[bags.length]){ System.out.print(bags.length); } System.out.println(); } private void calSolution(){ while(null != current.parent){ this.bestX[current.level] = current.choose; current = current.parent; } } private float bound(int level){ float max = 0; int available = 0; if(0 == level){ max = 0; available = this.capacity; }else{ max = current.currentValue; available = this.capacity - current.currentWeight; } //use the result of full knapsack with capacity 'available' as the bound while(level < bags.length && bags[level].weight <= available){ available -= bags[level].weight; max += bags[level].value; level++; } if(level < bags.length){ max += available * bags[level].price; } return max; } private class Node implements Comparable<Node>{ int level; int currentValue; int currentWeight; float upBound; boolean choose; Node parent; @Override public int compareTo(Node o) { if(this.upBound < o.upBound) return 1; else return -1; } public Node(int level, int currentValue, int currentWeight, float upBound, boolean choose, Node parent) { super(); this.level = level; this.currentValue = currentValue; this.currentWeight = currentWeight; this.upBound = upBound; this.choose = choose; this.parent = parent; } } private static class Bag implements Comparable<Bag>{ int weight; int value; float price; public Bag(int weight, int value) { super(); this.weight = weight; this.value = value; this.price = (float)value / (float)weight; } @Override public int compareTo(Bag other) { if((this.price- other.price) < 0) return 1; else return -1; } } }
动态规划:由于大多数情况下,部分子问题不用求解,故适合采用备忘录方法
import java.util.ArrayList; import java.util.Collections; import java.util.List; public class Knapsack { private int W; private int n; private int[] w; private int[] v; private int[][] f; private int countCall = 0; public Knapsack(int W, int n, int[] w, int[] v){ this.W = W; if(n != w.length || n != v.length){ throw new IllegalArgumentException(); } this.n = n; this.w = w; this.v = v; this.f = new int[n + 1][W + 1]; } /** * 0-1背包问题,对于K相对物品个数n较大的情况,备忘录方法效率更高 * 它可以避免计算一些不可达的子问题空间 * * @return the */ public int oneZeroKnapsack(){ for(int i = 0; i <= n; i++) for(int j = 0; j <= W; j++) f[i][j] = Integer.MAX_VALUE; return lookup_chain(n , W); } public void showObjects(){ int i = n , j = W; while(i > 0){ if(f[i][j] != f[i-1][j]){ System.out.println(i); j -= w[i-1]; } i--; } } private int lookup_chain(int i , int j){ countCall++; if( Integer.MAX_VALUE != f[i][j]) return f[i][j]; if( i <= 0 || j <= 0 ) return 0; if(w[i-1] > j){ f[i][j] = lookup_chain(i-1, j); } else{ int choose = lookup_chain(i-1, j-w[i-1]) + v[i-1]; int noChoose = lookup_chain(i-1 ,j); if(choose > noChoose) f[i][j] = choose; else f[i][j] =noChoose; } return f[i][j]; } private class Node implements Comparable<Node>{ int weight; private int value; int seq; float price; public Node(int weight, int value , int seq){ this.weight = weight; this.value = value; this.seq = seq; this.price = value / weight; } @Override public int compareTo(Node o) { if (o.price - this.price > 0) return 1; else return -1; } } }
DP算法:对于物品重量较小,且背包容量C=O(N)时,适合采用传统的自底向上的DP算法(时间复杂度为O(CN))。但此场景比较少见,故未给出该算法
相关文章推荐
- 0-1背包问题
- DP背包问题
- 背包问题的方案数(01)
- 背包九讲问题的模板
- HDU _2546 01背包问题
- 实用算法的分析与程序设计——递归法(实例,代码)(划分问题、0-1背包问题)
- USACO Score Inflation,完全背包问题
- Backpack 解题报告 背包问题深入浅出
- 51Nod-1597-有限背包计数问题
- rnqoj 98 逃亡的准备 多重背包问题
- 可以用贪心解决的背包问题
- [转载]背包问题九讲(九)
- hdu - 2660 Accepted Necklace (二维费用的背包问题)
- 动态规划之0-1背包问题(C实现)
- 背包问题
- 网易2017实习生编程题—双核处理问题(0-1背包问题)
- 0-1背包问题
- 背包问题详细分析
- 0/1背包问题
- 牛牛的背包问题