【Java实现】动态规划算法解决01背包问题

1、问题描述:

一个旅行者有一个最多能装m公斤的背包,现在有n中物品,每件的重量分别是W1、W2、……、Wn,每件物品的价值分别为C1、C2、……、Cn, 需要将物品放入背包中,要怎么样放才能保证背包中物品的总价值最大?

2、动态规划算法的概述

1)动态规划(Dynamic Programming)算法的核心思想是:将大问题划分为小问题进行解决,从而一步步获取最优解的处理算法

2)动态规划算法与分治算法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。

3)与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。 ( 即下一个子阶段的求解是建立在上一个子阶段的解的基础上,进行进一步的求解 )

4)动态规划可以通过填表的方式来逐步推进,得到最优解

3、解题思路

利用动态规划来解决,每次遍历到的第i个物品,根据 w[i]和v[i]来确定是否需要将该物品放入背包中。

对于给定的n个物品,

v[i]:第i个物品的价值

w[i]:第i个物品的重量

c:为背包的容量

v[i][j]表示在前i个物品中能够装入容量为j的背包中的最大价值。

1)v[i][0]=v[0][j]=0,表示第一行和第一列是0。

2)当w[i]>j时:v[i][j]=v[i-1][j] ,当准备加入新增的物品的容量大于当前背包的容量时,就直接使用上一个单元格的装入

3)当j>=w[i]时:v[i][j]=max{v[i-1][j] ,v[i]+v[i-1][j-w[i]]},当准备加入的新增的物品的容量小于等于当前背包的容量。

其中:

v[i-1][j]:就是上一个单元格的装入的最大值

v[i]:表示当前物品的价值

v[i-1][j-w[i]]:装入i-1物品,到剩余空间j-w[i]的最大值

【Java实现】动态规划算法解决01背包问题_第1张图片

4、完整代码及运行结果

package com.example.demo;

public class DynamicProgramming {
    public static void main(String[] args) {
        //物品的重量
        int[] c = {7, 2, 6, 3, 5};
        //物品的价值
        int[] w = {21, 18, 9, 15, 6};
        //物品的个数
        int n = w.length;
        //背包的容量
        int v = 14;

        knapsackDP(c, w, n, v);

    }


    /**
     *利用动态规划来解决:
     * 每次遍历到的第i个物品,根据 w[i]和v[i]来确定是否需要将该物品放入背包中。
     * 对于给定的n个物品,
     * v[i]:第i个物品的价值
     * w[j]:第i个物品的重量
     * c:为背包的容量
     * v[i][j]表示在前i个物品中能够装入容量为j的背包中的最大价值。
     *
     * @param w   物品的重量
     * @param val 物品的价值
     * @param n   物品的个数
     * @param m   背包的容量
     * @return
     */
    public static int knapsackDP(int[] w, int[] val, int n, int m) {
        //v[i][j] 表示在前i个物品中能够装入容量为j的背包中的最大价值
        int[][] v = new int[n + 1][m + 1];
        //记录放入物品的情况
        int[][] records = new int[n + 1][m + 1];

        //初始化第一行和第一列为0
        for (int i = 0; i < v.length; i++) {
            v[i][0] = 0;
        }
        for (int i = 0; i < v[0].length; i++) {
            v[0][i] = 0;
        }

        for (int i = 1; i < v.length; i++) {
            for (int j = 1; j < v[0].length; j++) {
                //当w[i]>j时,数组下标从1开始,所以-1
                if (w[i - 1] > j) {
                    v[i][j] = v[i - 1][j];
                } else {//当j>=w[i]时,数组下标从1开始,所以-1
                    if (v[i - 1][j] < val[i - 1] + v[i - 1][j - w[i - 1]]) {
                        v[i][j] = val[i - 1] + v[i - 1][j - w[i - 1]];
                        //记录
                        records[i][j] = 1;
                    } else {
                        v[i][j] = v[i - 1][j];
                    }

                }
            }
        }

        //
        for (int i = 0; i < v.length; i++) {
            for (int j = 0; j < v[i].length; j++) {
                System.out.print(v[i][j] + " ");
            }
            System.out.println();
        }

        System.out.println("============================");
        //行的最大下标
        int i = records.length - 1;
        //列的最大下标
        int j = records[0].length - 1;
        while (i > 0 && j > 0) { //从records的最后开始找
            if (records[i][j] == 1) {
                System.out.printf("第%d个物品放入到背包\n", i);
                j -= w[i - 1]; //w[i-1]
            }
            i--;
        }
        return 0;
    }
}

程序运行结果:

【Java实现】动态规划算法解决01背包问题_第2张图片

你可能感兴趣的:(数据结构与算法,Java,算法,动态规划,java)