笔试算法—《多重背包问题》

题目

  • N种物品和一个容量为V的背包,第i种物品最多有Mi件可用,每件物品消耗的容量为Ci,价值为Wi,求解入哪些物品可以使得背包中总价值最大。

思路

  • 思路:

  • 1,利用二维数据,构造一个表: dp[i][j]表示将前i件物品装进限重为j的背包可以获得的最大价值, 0<=i<=N, 0<=j<=V
    容量数组:V[i] 0<=i<=N
    价值数组:W[i] 0<=i<=N
    物品数量:M[i] 0<=i<=N

    • 1, 用k标识每件物品放入的数量,那么 k=min(M[i],j/V[i]) 就是说如果放入数量达到M[i]件,就不再放入该件物品
    • 2,若 j
    • 3,若果 j> Ci ,装入第i件物品, dp[i][j]=max(dp[i-1][j],max{dp[i-1][j-kV[i]]+kWi})
      注:完全背包就是,用已经放入的物品V[i]总价值kW[i](kW[i]就是数量乘价值等于总价值)加上剩余容量可以放入的物品价值dp[i-1][j-k*V[i]],
      k在可取范围(0

举例

  • 容量为10,有个 3,4,6,2四件物品价格分别为2,1,6,3,数量每件物品限制为3件(也可以每件分布限制数量)。
    第一步:放入物品 3,价值为2: 根据体积可以计算,可以重复放入3,最多放入3件,k=min[3,10/3] ,价值为6。
    笔试算法—《多重背包问题》_第1张图片
    第二步:放入物品4,价值为1
    (当放入4,根据公式计算,到后面一直到10,最多放入两个4,价值为2,都没有上一步价值高,所以取上面的值)
    笔试算法—《多重背包问题》_第2张图片
    第三步:放入物品6,价值为6,最多放入1个6,小于限制的数量3,正常放入
    (当放入6,根据公式,到9之后,9-6=3,当前列3下面是2,所以6+2=8
    笔试算法—《多重背包问题》_第3张图片
    第四步:放入物品2,价值为3
    (当放入2,后到4的时候,查找4-2=2,当前列2下面是3,所以是3+3=6) 放入2个
    (当放入2,后到6的时候,查找6-2=4,当前列4下面是6,所以是3+6=9) 放入3个
    (当放入2,6以及以后最多三个,价值为9,当到10的时候,发现k=2,也就是两个2,10-2*2=6,6下面是6,加上两个2的价值6:6+6=12) 放入:两个2一个6得最大值
    (当放入2,后到10的时候,查找10-2=8,当前列8下面是12,所以是3+12=15)

笔试算法—《多重背包问题》_第4张图片
所以,最终结果为 : 12

代码

  • 递推:
 public static void main(String[] args) {
     
        Scanner scanner = new Scanner(System.in);
        //容量
        int W = scanner.nextInt();

        //物品体积
        int[] N = {
     0, 3, 4, 6, 2};

        //物品对应的价值
        int[] V = {
     0, 2, 1, 6, 3};

        //物品对应数量
        int[] P = {
     0, 3, 3, 3, 3};

        int[][] dp = new int[N.length + 1][W + 1];

        for (int i = 1; i < N.length; i++) {
     
            for (int j = 1; j <= W; j++) {
     
                if (j < V[i]) {
     
                    dp[i][j] = dp[i - 1][j];
                } else {
     
                    int k = j / N[i];
                    int max = 0;
                    //c=min(P[i],j/N[i]) 取最大值
                    for (int c = 0; c <= k && c <= P[i]; c++) {
     
                        int result = dp[i - 1][j - c * N[i]] + c * V[i];
                        if (result > max) {
     
                            max = result;
                        }
                    }
                    int result = Math.max(max, dp[i - 1][j]);
                    dp[i][j] = result;
                }
            }
        }

        //输出二维表
        System.out.printf("%3s", "");
        for (int i = 0; i <= W; i++) {
     
            System.out.printf("%3s", i);
        }
        System.out.println();
        for (int i = 0; i < N.length; i++) {
     
            System.out.printf("%3s", N[i]);
            for (int j = 0; j < dp[i].length; j++) {
     
                System.out.printf("%3s", dp[i][j]);
            }
            System.out.printf("%3s", V[i]);
            System.out.println();
        }
        System.out.println(dp[N.length - 1][W]);
    }
- 递归
public  class 多重背包之递归 {
     
    private static int[] V={
     0,3,4,6,2};
    private static int[] P={
     0,2,1,6,3};
    private static int[] M={
     0,3,3,3,3};
    private static int T = 15;

    private Integer[][] results = new Integer[P.length + 1][T + 1];

    @Test
    public void solve2() {
     
        int result = ks2(P.length - 1,T);
        System.out.println("最大价值为:" + result);
    }

    private int ks2(int i, int t){
     
        // 如果该结果已经被计算,那么直接返回
        if (results[i][t] != null) return results[i][t];
        int result = 0;
        if (i == 0 || t == 0){
     
            // 初始条件
            result = 0;
        } else if(V[i] > t){
     
            // 装不下该珠宝
            result = ks2(i-1, t);
        } else {
     
            // 可以装下
            // 取k个物品,取其中使得价值最大的
            for (int k = 0; k <= M[i] && k * V[i] <= t; k++){
     
                int tmp2 = ks2(i-1, t - V[i] * k) + P[i] * k;
                if (tmp2 > result){
     
                    result = tmp2;
                }
            }
        }
        results[i][t] = result;
        return result;
    }
}

你可能感兴趣的:(面试,算法系列,leetcode,算法,动态规划,数据结构,java,leetcode)