zoukankan      html  css  js  c++  java
  • 0-1背包问题

    背包问题:n种物品,每种物品有重量w和价值v,背包所能承受的最大重量为c。如何挑选物品可以使总物品的价值最大。

    0-1背包问题:限定每种物品的个数只能是0或1.

    如:5个物品,质量分别为3,5,7,8,9,价值分别为4,6,7,9,10。背包所能承受重量为22.

    给物品从0开始编号,挑选物品1,3,4(价值分别为6,9,10)时,总价值最大为25,此时重量为22.

    运用动态规划思想,可以构造有效的方法。

    算法基本思路:

    1.构造最优表,获取最大价值;

    构造表mv[0...n][0...c],mv[i][j] 表示 前 i 项物品(即0到i-1)中挑选物品放入承受重量为 j 的最大价值。

    显然,当 i 为0即没有物品时,mv[0][*] = 0;当 j 为0即最大重量为0时,mv[*][0] = 0。(*表示任意)

    对于mv[i][j]只有两种可能的情况,

    (要注意的是,i 表示前i 项物品,物品编号从0开始,即 i-1 表示第i 项物品)

    (1)当w[i-1] > j 即当前物品重量大于当前最大承受重量时,只能放弃当前物品即 mv[i][j] = mv[i-1][j];

    (2)当w[i-1] <= j 即当前物品重量小于当前最大承受重量时,通过比较取此物品后的最大价值(即mv[i-1][j-w[i-1]] + v[i-1])与不取此物品的最大价值(即mv[i-1][j]),挑出较大值即 mv[i][j] = max(mv[i-1][j], mv[i-1][j-w[i-1]])。

    通过上述自底向上打表,可构造出最优值mv[n][c]。

    2.通过最优表,获取构造路线即挑出可以得到最大价值的物品。

    通过上述可知,当w[i-1] > j 时,mv[i][j] = mv[i-1][j];当w[i-1] <= j 时,mv[i][j] = max(mv[i-1][j], mv[i-1][j - w[i-1]] + v[i-1])。

    逆推此过程,从mv[n][c]出发,一直到 i 为 0(没有物品)或 j 为 0(没有更多重量)。

    当w[i-1] > j 时,可知没有挑选此物品,此时 i - 1;

    当w[i-1] <= j 时,再比较 mv[i][j] 是否与 mv[i-1][j] 相等,若是,则没有挑选此物品,此时 i - 1;若不等,则说明有挑选此物品,此时 i - 1, j - w[i-1]。

    算法实现:

    基本上和上述类似,但需要注意的是,返回结果,我同时返回了最优值和物品编号,涉及一些java处理字符串的小技巧,和此算法无关,可以忽略。

    /*
    input:     w[0..n-1]            //w[i] = the weight of Object i
            v[0..n-1]            //v[i] = the value of Object i
            c                      //c = the weight of Knapsack
    
    table:    mv[0..n][0..C]        //mv[i][j] = select some objects from O[0..i-1], then satify the max value(weight < weight j)
    
    if i = 0, means no objects, so mv[0][*] = 0
    if j = 0, means no weights, so mv[*][0] = 0
    else    if w[i-1] > j, means not enough weight, so mv[i][j] = mv[i-1][j]
            if w[i-1] <= j, means enough weight, so mv[i][j] = min(mv[i-1][j], mv[i-1][j-w[i-1]] + v[i-1])
            //note that mv[i-1][j-w[i]] means the best answer of O[0..i-1] in weight j-w[i-1]
            //note that i means ith object, so it is w[i-1] rather than w[i]
    */
    
    import java.util.ArrayList;
    
    public class Knapsack {
        
        public static String getMaxValue(int[] w, int[] v, int c){
            int[][] mv = new int[w.length+1][c+1];
            //i = 0
            for(int j = 0; j <= c; j ++){
                mv[0][j] = 0;
            }
            //j = 0
            for(int i = 0; i <= w.length; i ++){
                mv[i][0] = 0;
            }
            //compute
            for(int i = 1; i < mv.length; i ++){
                for(int j = 1; j <= c; j ++){
                    if(w[i-1] > j){
                        mv[i][j] = mv[i-1][j];
                    }
                    else{
                        mv[i][j] = Math.max(mv[i-1][j], mv[i-1][j-w[i-1]] + v[i-1]);
                    }
                }
            }
    //        for(int i = 0; i < mv.length; i ++){
    //            for(int j = 0; j < mv[0].length ; j ++){
    //                System.out.print(mv[i][j] + " ");
    //            }
    //            System.out.println();
    //        }
            //get result
            ArrayList<Integer> index = getObjectsIndex(w, v, c, mv);
            String result = Integer.toString(mv[w.length][c]);
            for(int i = 0; i < index.size(); i ++)
                result += "/" + Integer.toString(index.get(i));
            return result;
        }
    
        private static ArrayList<Integer> getObjectsIndex(int[] w, int[] v, int c, int[][] mv){
            ArrayList<Integer> index = new ArrayList<Integer>();
            int i = mv.length-1, j = c;
            while(i > 0 && j > 0){
                if(w[i-1] > j){
                    i --;
                }
                else{
                    if(mv[i-1][j] == mv[i][j]){
                        i --;
                    }
                    else{
                        index.add(i-1);
                        j -= w[i-1];
                        i --;
                    }
                }
            }
            return index;
        }
    
        public static void main(String[] args) {
            int c = 22;
            int[] w = {3, 5, 7, 8, 9};
            int[] v = {4, 6, 7, 9, 10};
            String[] result = getMaxValue(w, v, c).split("/");
            System.out.println(result[0]);
            for(int i = 1; i < result.length; i ++)
                System.out.print(result[i] + " ");
            System.out.println();
        }
    
    }
    Java
  • 相关阅读:
    Java实现 LeetCode 343 整数拆分(动态规划入门经典)
    Java实现 LeetCode 342 4的幂
    Java实现 LeetCode 342 4的幂
    Java实现 LeetCode 342 4的幂
    Java实现 LeetCode 341 扁平化嵌套列表迭代器
    Java实现 LeetCode 341 扁平化嵌套列表迭代器
    Java实现 LeetCode 341 扁平化嵌套列表迭代器
    Java实现 LeetCode 338 比特位计数
    H264(NAL简介与I帧判断)
    分享一段H264视频和AAC音频的RTP封包代码
  • 原文地址:https://www.cnblogs.com/7hat/p/3445861.html
Copyright © 2011-2022 走看看