java动态规划 牛妹的礼物(图解)

题目描述
众所周知,牛妹有很多很多粉丝,粉丝送了很多很多礼物给牛妹,牛妹的礼物摆满了地板。
地板是N\times MN×M的格子,每个格子有且只有一个礼物,牛妹已知每个礼物的体积。
地板的坐标是左上角(1,1) 右下角(N, M)。
牛妹只想要从屋子左上角走到右下角,每次走一步,每步只能向下走一步或者向右走一步或者向右下走一步
每次走过一个格子,拿起(并且必须拿上)这个格子上的礼物。
牛妹想知道,她能走到最后拿起的所有礼物体积最小和是多少?
题目链接
一道简单的动态规划入门题。
对于之前没有接触过动归的人,动归的题往往让然看起来不知道从何下手。
前两天在b站看了一个up讲的动态规划让我这种之前没有系统学习过动归的有了更深的理解,up叫正月点灯笼,大家感兴趣的可以去看看。
我觉得动归很多时候都是一个我们要在解决问题的时候找到每一步最好的选择的过程。

如果只走一步,走到2。我们有三种走法,从1走到2或者从6走到2,或者从8走到2。其中最好的选择时从1走到2。
换句话说,只走一步的情况下,我们可以找到走到2的最优解。可是实际上会有更多的格子。

这时候我们如果仍然是从左上角出发把2作为目的地的话,那么通过1走到2就不在是最好的选择了。
那么我们怎么可以把这个局部的最优解扩大到全局,获得我们的最终想要的结果呢?
其实很简单,就是保证我们从左上角出发开始,选择走的每一步都是最优解即可。
在这里插入图片描述
我们不难发现想要走到蓝色的部分只能是来自他的上方或者左方。我们可以求出蓝色部分的最优解。
举例:在这里插入图片描述
剩下的格子的最优解就是从它的上方、左方、左上方中选择负重最小的。

这样当我们走到最后一个格子的时候就求出了最优解。
代码如下:

import java.util.*;


public class Solution {
    /**
     * 
     * @param presentVolumn int整型二维数组 N*M的矩阵,每个元素是这个地板砖上的礼物体积
     * @return int整型
     */
    public int selectPresent (int[][] presentVolumn) {
        // write code here
        if(presentVolumn.length == 0) {
            return 0;
        }
        int[][] ret = presentVolumn;
        //初始化第一行第一列的最优解
        if(ret[0].length > 1) {
            for (int i = 1; i < ret[0].length; i++) {
                ret[0][i] += ret[0][i - 1];
            }
        }
        if(ret.length > 1) {
            for (int i = 1; i < ret.length; i++) {
                ret[i][0] += ret[i - 1][0];
            }
        }
        if(ret.length == 1) {
            return ret[0][ret[0].length - 1];
        }
        if(ret[0].length == 1) {
            return ret[ret.length - 1][0];
        }
        for (int i = 1; i < ret.length; i++) {
            for (int j = 1; j < ret[0].length; j++) {
                ret[i][j] += Integer.min(ret[i - 1][j - 1], Integer.min(ret[i - 1][j], ret[i][j - 1]));
            }
        }
        return ret[ret.length - 1][ret[0].length - 1];
    }
}

代码中需要注意的几点:1.用例中会有presentVolumn.length == 0的情况,需要单独处理或者会报出越界。
2.需要考虑到只有一行或者只有一列的特殊情况。
3.在二维数组中行的长度=有多少列 列的长度=有多少行

希望可以帮助你,觉得还不错的话点个赞吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值