博客
关于我
【数算-31】【十大常用算法-03】动态规划算法与背包问题
阅读量:325 次
发布时间:2019-03-04

本文共 3098 字,大约阅读时间需要 10 分钟。

动态规划算法是解决许多复杂问题的有效方法,特别是在处理有重叠子问题和最优子结构性质的问题时。动态规划的核心思想是通过分解问题,将大问题转化为多个小问题来解决,并通过记录中间结果避免重复计算,从而提高效率。

动态规划算法概述

动态规划常常适用于以下类型的问题:

  • 最优子结构性质:问题的最优解可以由较小的子问题的最优解构成。
  • 重叠子问题性质:递归算法中多次计算相同的子问题,动态规划通过记录结果减少重复计算。
  • 背包问题

    0/1背包问题是最经典的动态规划应用之一。问题描述是:给定多个物品,每个物品只能选择完全装入背包或不装入,求背包中总价值的最大值。

    问题描述

    • 物品重量:各不相同。
    • 物品价值:各不相同。
    • 背包容量:固定值。

    目标是选择物品的组合,使得总价值最大,同时不超过背包容量。

    思路分析

    动态规划常用备忘录法解决背包问题。通过创建二维数组记录不同容量和物品组合下的最大价值。

    解决问题的策略

  • 初始化:创建二维数组res记录最大价值,path记录物品装入情况。
  • 填充表格
    • 若物品重量大于剩余容量,取上一行当前列的值。
    • 否则,比较不放和放当前物品的价值,取较大值,并记录物品装入情况。
  • 代码实现

    private int[][] knapsack(int[] weight, int[] value, int capacity) {    int num = weight.length;    int[][] res = new int[num + 1][capacity + 1];    int[][] path = new int[num + 1][capacity + 1];        for (int i = 0; i < res.length; i++) {        res[i][0] = 0;    }    for (int i = 0; i < res[0].length; i++) {        res[0][i] = 0;    }        for (int i = 1; i < res.length; i++) {        for (int j = 1; j < res[i].length; j++) {            if (weight[i - 1] > j) {                res[i][j] = res[i - 1][j];            } else {                if (res[i - 1][j] < value[i - 1] + res[i - 1][j - weight[i - 1]]) {                    res[i][j] = value[i - 1] + res[i - 1][j - weight[i - 1]];                    path[i][j] = 1;                } else {                    res[i][j] = res[i - 1][j];                }            }        }    }    int i = path.length - 1;    int j = path[0].length - 1;    while (i > 0 && j > 0) {        if (path[i][j] == 1) {            System.out.println("第" + i + "个物品被装入背包");            j -= weight[i - 1];        }        i--;    }    return res;}

    代码测试

    @Testpublic void test() {    int[] weight = {1, 4, 3};    int[] value = {1500, 3000, 2000};    int capacity = 4;    int[][] knapsack = knapsack(weight, value, capacity);    for (int[] each : knapsack) {        System.out.println(Arrays.toString(each));    }}

    优化后的代码

    为了更清楚地了解装入物品,可以增加路径数组记录物品装入情况。

    private int[][] knapsack(int[] weight, int[] value, int capacity) {    int num = weight.length;    int[][] res = new int[num + 1][capacity + 1];    int[][] path = new int[num + 1][capacity + 1];        for (int i = 0; i < res.length; i++) {        res[i][0] = 0;    }    for (int i = 0; i < res[0].length; i++) {        res[0][i] = 0;    }        for (int i = 1; i < res.length; i++) {        for (int j = 1; j < res[i].length; j++) {            if (weight[i - 1] > j) {                res[i][j] = res[i - 1][j];            } else {                if (res[i - 1][j] < value[i - 1] + res[i - 1][j - weight[i - 1]]) {                    res[i][j] = value[i - 1] + res[i - 1][j - weight[i - 1]];                    path[i][j] = 1;                } else {                    res[i][j] = res[i - 1][j];                }            }        }    }    int i = path.length - 1;    int j = path[0].length - 1;    while (i > 0 && j > 0) {        if (path[i][j] == 1) {            System.out.println("第" + i + "个物品被装入背包");            j -= weight[i - 1];        }        i--;    }    return res;}

    测试结果

    运行结果显示了二维数组res,其中res[i][j]表示装入i个物品时,背包容量为j时的最大价值。路径数组path记录了每个状态是否放入物品,帮助理解背包中装入了哪些物品。

    通过动态规划算法,我们可以高效地解决背包问题,找到最大价值的装入组合。

    转载地址:http://jxgh.baihongyu.com/

    你可能感兴趣的文章
    求n内的素数,并打印出来(c语言)
    查看>>
    [电影]《Ladybird》演绎完整18岁的青春
    查看>>
    树莓派博通BCM2835芯片的IO口驱动代码调试和测试
    查看>>
    npm问题汇总
    查看>>
    Vue快速入门学习笔记(更新ing)
    查看>>
    js中[]、{}、()的区别
    查看>>
    js-禁止右键菜单代码、禁止复制粘贴代码
    查看>>
    血色先锋队
    查看>>
    win10系统安装配置Go环境包(第0章)
    查看>>
    搭建samba服务器
    查看>>
    Java: 错误: 不支持发行版本 5
    查看>>
    顺序表的操作总结
    查看>>
    【笔记】大数据技术之流计算Storm(十)
    查看>>
    Java基础语法
    查看>>
    原创-开发问题指南
    查看>>
    文本情感分类
    查看>>
    Python模块_os文件_目录方法
    查看>>
    部署kuboard3 管理工具
    查看>>
    SpringBoot中使用Mybatis访问MySQL数据库(使用xml方式)
    查看>>
    Algorithms Unlocked
    查看>>