0-1背包问题

回溯法:适用于背包容量C远大于物品个数N,时间复杂度O(2*N )

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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值