01背包问题:递归、动态规划求解

01背包问题:递归、动态规划求解

//使用记忆化搜索:(存在重叠子问题:对于index,c这一数据对可能求解多次)
    int[][] memo;
    /**
     * 用[0...index]的物品,填充容积为c的背包的最大价值
     * @param w:物体的重量
     * @param v:物体的价值
     * @param index:当前考虑的物体的index序列号
     * @param c:当前所剩容量
     * @return
     */
    private int bestValue(int[] w,int[] v,int index, int c){
     
        //递归的终止条件:没有物体可以放,或者当前剩下的容量为0
        if(index <0 || c<=0){
     
            return 0;
        }
        // 判断memo[index][c]中是否有值,有值的话不用继续多余重复的计算了,直接返回
       if(memo[index][c] != -1){
     
            return memo[index][c];
       }

        //尝试向背包中放入新的物品
        //第一种情况:当前的物品不放入背包中,从[0...index-1]的来填充
        int res = bestValue(w,v,index-1,c);
        //第二种情况:当前的物品放入背包中
        if(c >= w[index]){
     
            //当前物品的重量可以放进去
            //与第一种情况去最大值
           res = Math.max(res,v[index]+ bestValue(w,v,index-1,c-w[index]));
        }
        memo[index][c] = res;
        return res;
    }

    /**
     * 01背包问题:递归算法(自顶向下)
     * @param w
     * @param v
     * @param C
     * @return
     */
    public int package01(int[] w,int[] v,int C){
     
        int n = w.length;
        //n个物品,背包的容量为0-C,为C+1
        memo = new int[n][C+1];
        for(int i=0;i<n;i++){
     
            for(int j=0;j<C+1;j++){
     
                memo[i][j] = -1;
            }
        }
        return  bestValue(w,v,n-1,C);
    }
  /**
     * 01背包问题:动态规划(自底向上)
     * @param w
     * @param v
     * @param C
     * @return
     */
    public int package01Sec(int[] w,int[] v,int C){
     
        int n= w.length;
        if(w.length != v.length || n ==0){
     
            return 0;
        }
        int[][] memo = new int[n][C+1];
        for(int i=0;i<n;i++){
     
            for(int j=0;j<C+1;j++){
     
                memo[i][j] = -1;
            }
        }

        //先处理最基础的问题:memo[0][j]第0行的每一个元素的值:遍历列
        for(int j=0;j<=C;j++){
     
            //只考虑0这个物品,j为背包的容量:能否放进第0个物品
            memo[0][j] = j >= w[0]? v[0]:0;
        }
        //递推的过程
        for(int i=1;i<n;i++){
     
            //逐行解决
            for (int j =0; j<=C;j++){
     
                //逐列解决:在每一列中计算出memo[i][j]:考虑0-i的物品,且容积为j获得的最大值
                //第一种情况:不考虑第i个物品,不放进背包
                memo[i][j] = memo[i-1][j];
                //第二个情况:考虑第i个物品,放进背包:判断能放进去
                if(j>=w[i]){
     
                    memo[i][j] = Math.max(memo[i][j],v[i]+memo[i-1][j-w[i]]);
                }
            }
        }
        return memo[n-1][C];
    }
  /**
     * 01背包问题:动态规划(自底向上):改进:空间复杂度由O(n*C)变为O(2*C)
     * @param w
     * @param v
     * @param C
     * @return
     */
    public int package01SecMod(int[] w,int[] v,int C){
     
        int n= w.length;
        if(w.length != v.length || n ==0){
     
            return 0;
        }
        int[][] memo = new int[2][C+1];
        for(int i=0;i<2;i++){
     
            for(int j=0;j<C+1;j++){
     
                memo[i][j] = -1;
            }
        }

        //先处理最基础的问题:memo[0][j]第0行的每一个元素的值:遍历列
        for(int j=0;j<=C;j++){
     
            //只考虑0这个物品,j为背包的容量:能否放进第0个物品
            memo[0][j] = j >= w[0]? v[0]:0;
        }
        //递推的过程
        for(int i=1;i<n;i++){
     
            //逐行解决
            for (int j =0; j<=C;j++){
     
                //逐列解决:在每一列中计算出memo[i][j]:考虑0-i的物品,且容积为j获得的最大值
                //第一种情况:不考虑第i个物品,不放进背包
                memo[i%2][j] = memo[(i-1)%2][j];
                //第二个情况:考虑第i个物品,放进背包:判断能放进去
                if(j>=w[i]){
     
                    memo[i%2][j] = Math.max(memo[i%2][j],v[i]+memo[(i-1)%2][j-w[i]]);
                }
            }
        }
        return memo[(n-1)%2][C];
    }
  /**
     * 01背包问题:动态规划(自底向上):改进:空间复杂度由O(2*C)就是O(C)
     * @param w
     * @param v
     * @param C
     * @return
     */
    public int package01SecModSec(int[] w,int[] v,int C){
     
        int n= w.length;
        if(w.length != v.length || n ==0){
     
            return 0;
        }
        int[] memo = new int[C+1];
        for(int i=0;i<C+1;i++){
     
                memo[i] = -1;
        }

        //先处理最基础的问题:memo[j]第0行的每一个元素的值:遍历列
        for(int j=0;j<=C;j++){
     
            //只考虑0这个物品,j为背包的容量:能否放进第0个物品
            memo[j] = j >= w[0]? v[0]:0;
        }
        //递推的过程
        for(int i=1;i<n;i++){
     
            //逐行解决
            for (int j =C; j>=w[i];j--){
     
                //逐列解决:在每一列中计算出memo[j]:考虑0-i的物品,且容积为j获得的最大值
                    memo[j] = Math.max(memo[j],v[i]+memo[j-w[i]]);
            }
        }
        return memo[C];
    }

你可能感兴趣的:(算法,算法)