0/1揹包問題的通用模板

以lintcode 92爲例。
整體架構如下:
0/1-knapsack
代碼:

import java.util.Arrays;

public class Solution {
	
	/**
	 * 是否可以全部選擇
	 */
	private int fullSelect(int[] A,int m){
		int sum=0;
		for(int key:A){
			sum+=key;
		}
		return sum;
	}
	
	/**
	 * 貪心選擇
	 */
	private int greedy(int[] A,int m){
		Arrays.sort(A);
		int sum=0;
		for(int i=A.length-1;i>=0;i--){
			if(sum+A[i]<m){
				sum+=A[i];
			}
		}
		return sum;
	}
	
	/**
	 * 全局變量,進行位運算
	 */
	private int totalKey=0;
	/**
	 * 全局變量,用來記錄最優解
	 */
	private int totalMax=0;
	private int resultKey=0;
	/**
	 * @param level 當前遞歸層數
	 * @param curr  當前重量
	 * @param res   剩餘重量
	 */
	private void dfs(final int[] A,final int m,final int n,int level,int curr,int res){
		if(level==n){
			//更新最優值
			if(curr>=totalMax){
				totalMax=curr;
				resultKey=totalKey;
			}
		}else{
			res-=A[level];
			//不選擇
			if(curr<=m&&curr+res>=totalMax){
				dfs(A, m, n, level+1, curr, res);
			}
			//第level位置1,選擇
			totalKey|=1<<level;
			curr+=A[level];
			//約束和剪枝
			if(curr<=m&&curr+res>=totalMax){
				dfs(A, m, n, level+1, curr, res);
			}
			//回溯,第level位置重新置爲0
			totalKey&=~(1<<level);
		}
	}
	
	/**
	 * 通過位運算還完最優解
	 */
	private int getResultBitManipulation(int[] A,int n){
		int sum=0;
		for(int i=0;i<n;i++){
			//判斷第i位是0還是1
			if((resultKey&1<<i)!=0){
				sum+=A[i];
			}
		}
		return sum;
	}
	
	/**
	 * 回溯剪枝解法
	 */
	public int backTrackSolution(int[] A,int m){
		int n=A.length;
		//使用貪心算法確定一個下界
		this.totalMax=greedy(A, m);
		int res=0;
		for(int key:A){
			res+=key;
		}
		dfs(A, m, n, 0, 0, res);
		return getResultBitManipulation(A, n);
	}
	
	public int dpSolution(int[] A,int m){
		int n=A.length;
		int[][] dp=new int[n+1][m+1];
		//計算最優值
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				//不放入i
				dp[i][j]=dp[i-1][j];
				if(j>=A[i-1]){
					//放入i,並把前i-1個物品放入容量爲j-A[i]的揹包
					dp[i][j]=Math.max(dp[i][j], dp[i-1][j-A[i-1]]+A[i-1]);
				}
			}
		}
		//根據最優值得到的信息,反向構造最優解
		int c=m;
		int[] vec=new int[n];
		for(int i=n;i>0;i--){
			if(dp[i][c]==dp[i-1][c]){
				vec[i-1]=0;
			}else{
				vec[i-1]=1;
				c-=A[i-1];
			}
		}
		int sum=0;
		for(int i=0;i<n;i++){
			if(vec[i]==1){
				sum+=A[i];
			}
		}
		return sum;
	}
    public int backPack(int m, int[] A) {
    	//邊界檢查
    	if(m==0||A==null||A.length==0){
    		return 0;
    	}
        int full=fullSelect(A, m);
        if(full<=m){
        	return full;
        }
        if(m<=16){
        	return backTrackSolution(A, m);
        }else{
        	return dpSolution(A, m);
        }
    }
}