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
  • 相关阅读:
    Android EditText内容监听
    Android模仿QQ空间图片上传——原理
    PHP新手入门1——表单
    linux下ftp常用命令
    TextView所有属性
    iOS开发-删除字典中的null
    去除导航栏下方的横线
    应用的启动视图 LauchView
    App所需申请资料
    应用本地化
  • 原文地址:https://www.cnblogs.com/7hat/p/3445861.html
Copyright © 2011-2022 走看看