动态规划之背包问题java语言+图解

下方转载的文章转移方程错误,请参考如下文章
https://blog.youkuaiyun.com/weixin_45036949/article/details/125275274
https://cloud.tencent.com/developer/article/2109843

转移方程
01背包问题,是用来介绍动态规划算法最经典的例子,网上关于01背包问题的讲解也很多,我写这篇文章力争做到用最简单的方式,最少的公式把01背包问题讲解透彻。

01背包的状态转换方程 f[i,j] = Max{ f[i-1,j-Wi]+Pi( j >= Wi ), f[i-1,j] }
f[i,j]表示在前i件物品中选择若干件放在承重为 j 的背包中,可以取得的最大价值。

博主自己写的代码 :

    public static int solution(int[] weights, int[] values, int bag) {
        //保证第一行,第一列为0
        int[][] dp = new int[weights.length+1][bag+1];
        dp[0][0] = 0;
        for (int i = 0; i < bag+1; i++) {
            dp[0][i] = 0;
        }
        for (int i = 0; i < weights.length+1; i++) {
            dp[i][0] = 0;
        }
        for(int i=1; i<weights.length+1; i++) {
            for(int j=1; j<bag+1; ++j) {
                if(j >= weights[i-1]) {
                    dp[i][j] = Math.max(dp[i-1][j], values[i-1] + dp[i-1][j-weights[i-1]]);
                }
                //打印过程
                System.out.print(String.format("%3d", dp[i][j]));
                if (j == bag) {
                    System.out.println(String.format("%3d", dp[i][j]));
                }
            }
        }
        return dp[weights.length][bag];
    }

    public static void main(String[] args) {
        System.out.println("最终结果:"+solution(new int[] {20, 30, 100}, new int[] {40, 50, 80}, 150));//170
    }

下方代码错误,以最上面的为准

public static int solution(int[] weights, int[] values, int bag) {
    //保证第一行,第一列为0
    int[][] dp = new int[weights.length + 1][bag + 1];
    //dp[0][0] = 0;
    for(int i=1; i<=weights.length-1; i++) {
        for(int j=1; j<=bag; ++j) {
            if(j >= weights[i]) {
                dp[i][j] = Math.max(dp[i-1][j], values[i] + dp[i-1][j-weights[i]]);
            }
            //打印过程
            System.out.print(String.format("%3d", dp[i][j]));
            if (j == bag) {
                System.out.println(String.format("%3d", dp[i][j]));
            }
        }
    }
    return dp[weights.length-1][bag];
}

public static void main(String[] args) {
    System.out.println("最终结果:"+solution(new int[] {0, 20, 30, 100}, new int[] {0, 40, 50, 80}, 100));
}
public class dp10 {
    public static int solution(int[] weights, int[] values, int bag) {
        //保证第一行,第一列为0
        int[][] dp = new int[weights.length + 1][bag + 1];
        //dp[0][0] = 0;
        for(int i=1; i<=weights.length; i++) {
            for(int j=1; j<=bag; ++j) {
                //dp[i][j] = dp[i + 1][j];
                //注意此处的dp的坐标与weights与values稍有差别
                if(j >= weights[i-1]) {
                    dp[i][j] = Math.max(dp[i-1][j], values[i-1] + dp[i-1][j-weights[i-1]]);
                }
                //打印过程
                System.out.print(String.format("%3d", dp[i][j]));
                if (j == bag) {
                    System.out.println(String.format("%3d", dp[i][j]));
                }
            }
        }
        return dp[weights.length][bag];
    }

    public static void main(String[] args) {
        System.out.println("最终结果:"+solution(new int[] {20, 30, 100}, new int[] {40, 50, 80}, 150));
    }
}
// 结果90

下文内容转载自:https://blog.youkuaiyun.com/XiaHeShun/article/details/79706744

最近碰到动态规划的01背包问题,然后我就再网上四处看帖子,对于我这样的小白白来说,觉得网上的帖子写的对于新手来说,都有些晦涩难懂,于是乎,我想着用代码和图的方式来结合说明一下,有不对的,望大家及时指正。

背景:
0/1背包问题是最基本的背包问题,它包含了背包问题中设计状态、方程的最基本思想,另外,别的类型的背包问题往往也可以转换成0/1背包问题求解。一定要仔细体会基本思路的得出方法,状态转移方程的意义,以及最后怎样优化的空间复杂度。


问题描述:

假设孙悟空去向观音求救,观音向孙悟空展示了五个宝物,分别为A、B、C、D、E,这五种宝物的重量分别为2吨、2吨、6吨、5吨、4吨,它们的价值分别为6法力、3法力、5法力、4法力、6法力,但是孙悟空可以拿走多个宝物,但是宝物的总重量最多为10吨。请问,孙悟空应该怎么取宝物,并在自己能够承受的重量范围之内,宝物的法力最高?

(让生活多点乐趣,跟大家画了一个精美的题目内容图解)

这里写图片描述


问题分析:
每个宝物都是独特的,都只有一份,背包有最大容量限定,然后取价值最高的最优解,这很明显就是动态规划中的一种特殊情况–背包问题。
我们可以通过简单的暴力搜索,但是如果讲到算法来说,暴力搜索的空间复杂度和时间复杂度就很糟糕了。


01背包算法–结果图解
我先直接给出结果图吧,然后我带着大家一起,从结果开始分析,我们慢慢回溯。
下面给的表格矩阵,也就是最终的结果矩阵,首先我解释一下几个变量的意思。

  1. weight :重量
  2. value:法力值
  3. content:背包容量
  4. name:宝物的名字

这里写图片描述


01背包算法–结果图解
对比着结果,我们来推一下01背包算法的转移方程:

arr[i][j]=MAX{arr[i1][jweight[i1]]+value[i1](j>=weight[i1]),arr[i1][j]}arr[i][j]=MAX{arr[i−1][j−weight[i−1]]+value[i−1](j>=weight[i−1]),arr[i−1][j]}

这里写图片描述

看着转移方程,你可能会有点迷茫,我自己最初也是,但是只要你们推出来结果矩阵,那么,你就懂了。

这里写图片描述

转移算法是从矩阵的从左往右,从上往下进行遍历求解的。就是两层for循环,最外层是行循环,最内层是列循环。

敲黑板!!!你可能会发现我在这里是多设置了一行和一列的数据,并初始化为0。其实就是为了计算,因为每一个数据都需要用到上一行的数据,这也就是算法的精髓,将过去算过的结果记录下来,免去下一次的计算,老实讲,想到算法的人,前辈们真的很有智慧啊。

接下里,我举例说一下公式是怎么算数据的,我想有很多初学者肯定很蒙圈,我来跟你画出来。
这里写图片描述
在上图中,我列举出来的(D宝物行,背包容量为10列)坐标的取值过程,其它的过程同此一样。大家一定要尝试着自己手写递推一下,这样才能理解深刻!


于是乎,我给大家代码:

package travelling_bag;

public class Main {
    //分别定义宝物名称、重量、法力和背包最大容量
    public static String[] name = {"A","B","C","D","E"};
    public static int[] weight = {2,2,6,5,4};
    public static int[] value = {6,3,5,4,6};
    public static int  content = 10;
    //定义我们的记录矩阵,需要多一列和一行,也就是上面所给表中灰色的列,
    //因为我们下面的操作会设计到i-1和j-1,所以我们在这里需要多定义一行和一列
    public static int[][] arr = new int[name.length+1][content+1];

    public static int[][] bag(int[] weight, int[] value, int content, int[][] arr){
        for (int i = 1; i < arr.length; i++) { //行
            for (int j = 1; j < arr[i].length; j++) { //列
                if(j>=weight[i-1]){
                    arr[i][j] = arr[i-1][j-weight[i-1]]+value[i-1];
                }
                if(arr[i][j]<arr[i-1][j]){
                    arr[i][j]=arr[i-1][j];
                }

            }
        }
        return arr;
    }
    //就是定义看一下矩阵
    public static void show(){
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                System.out.print(arr[i][j]+"\t");
            }
            System.out.println();
        }
    }

    public static void main(String[] args) {
        arr = bag(weight,value,content,arr);
        show();
    }

}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

运行结果为:

0   0   0   0   0   0   0   0   0   0   0   
0   0   6   6   6   6   6   6   6   6   6   
0   0   6   6   9   9   9   9   9   9   9   
0   0   6   6   9   9   9   9   11  11  14  
0   0   6   6   9   9   9   10  11  13  14  
0   0   6   6   9   9   12  12  15  15  15  
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

结果应该还是很明显的,能带走的物品最大法力值为15。

  •                     <li class="tool-item tool-active is-like "><a href="javascript:;"><svg class="icon" aria-hidden="true">
                            <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#csdnc-thumbsup"></use>
                        </svg><span class="name">点赞</span>
                        <span class="count">4</span>
                        </a></li>
                        <li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;popu_824&quot;}"><svg class="icon" aria-hidden="true">
                            <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#icon-csdnc-Collection-G"></use>
                        </svg><span class="name">收藏</span></a></li>
                        <li class="tool-item tool-active is-share"><a href="javascript:;"><svg class="icon" aria-hidden="true">
                            <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#icon-csdnc-fenxiang"></use>
                        </svg>分享</a></li>
                        <!--打赏开始-->
                                                <!--打赏结束-->
                                                <li class="tool-item tool-more">
                            <a>
                            <svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg>
                            </a>
                            <ul class="more-box">
                                <li class="item"><a class="article-report">文章举报</a></li>
                            </ul>
                        </li>
                                            </ul>
                </div>
                            </div>
            <div class="person-messagebox">
                <div class="left-message"><a href="https://blog.youkuaiyun.com/XiaHeShun">
                    <img src="https://profile.csdnimg.cn/A/F/B/3_xiaheshun" class="avatar_pic" username="XiaHeShun">
                                            <img src="https://g.csdnimg.cn/static/user-reg-year/2x/2.png" class="user-years">
                                    </a></div>
                <div class="middle-message">
                                        <div class="title"><span class="tit"><a href="https://blog.youkuaiyun.com/XiaHeShun" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}" target="_blank">XiaHeShun</a></span>
                                            </div>
                    <div class="text"><span>发布了74 篇原创文章</span> · <span>获赞 118</span> · <span>访问量 9万+</span></div>
                </div>
                                <div class="right-message">
                                            <a href="https://im.youkuaiyun.com/im/main.html?userName=XiaHeShun" target="_blank" class="btn btn-sm btn-red-hollow bt-button personal-letter">私信
                        </a>
                                                            <a class="btn btn-sm  bt-button personal-watch" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}">关注</a>
                                    </div>
                            </div>
                    </div>
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值