一道偶然邂逅的动规引发的首篇随笔

个人业余爱好:以后会坚持每天至少一篇新随笔,希望大家多多监督、支持和交流~

摘要:这是博主第一篇追随算法学习的心得体会,关于一道简单的动态规划题目,力求简明扼要,聚焦交流学习~

正题:

1.抛出题目(对问题的初步理解):

* 众所周知,牛妹有很多很多粉丝,粉丝送了很多很多礼物给牛妹,牛妹的礼物摆满了地板。
* 地板是
* N×M的格子,每个格子有且只有一个礼物,牛妹已知每个礼物的体积。
* 地板的坐标是左上角(1,1) 右下角(N, M)。
* 牛妹只想要从屋子左上角走到右下角,每次走一步,每步只能向下走一步或者向右走一步或者向右下走一步
* 每次走过一个格子,拿起(并且必须拿上)这个格子上的礼物。
* 牛妹想知道,她能走到最后拿起的所有礼物体积最小和是多少?
题目出处:https://www.nowcoder.com/practice/c4f777778e3040358e1e708750bb7fb9?tpId=110&tqId=33431&tPage=1&rp=1&ru=%2Fta%2Fjob-code&qru=%2Fta%2Fjob-code%2Fquestion-ranking

2.输入输出示例(举一反三的理解题意,明确题目要实现的算法初始参数和最终返回):

输入:[[1,2,3],[2,3,4]]

输出:7

说明:按路径:(1,1)-> (1,2) -> (2,3) 走得到最小值。

3.分析:

一言可以概之,满足最优化问题最关键的两大必要条件:无后效性(未来决策与过去决策无关)和最优子策略(子问题可用同理的决策方法解决),是一道典型的动态规划问题,而且是动规中最简单的线性动规(通过线性结构解决足矣)。

4.例程:

/**
* 众所周知,牛妹有很多很多粉丝,粉丝送了很多很多礼物给牛妹,牛妹的礼物摆满了地板。
* 地板是
* N×M的格子,每个格子有且只有一个礼物,牛妹已知每个礼物的体积。
* 地板的坐标是左上角(1,1) 右下角(N, M)。
* 牛妹只想要从屋子左上角走到右下角,每次走一步,每步只能向下走一步或者向右走一步或者向右下走一步
* 每次走过一个格子,拿起(并且必须拿上)这个格子上的礼物。
* 牛妹想知道,她能走到最后拿起的所有礼物体积最小和是多少?
* 问题判型:最优化问题
* 解决方案:动态规划
* 逆向状态转换:如何走到右下方,首先前一步须要在右下方的周围,推出走到格子(n,m)的礼物体积最小和的状态转移方程:
* min[n][m] = min{min[n - 1][m], min[n - 1][m - 1], min[n][m - 1]} + a[n][m]
* 同时要检查计算出来的方程是否有解,须要满足的条件是:
* 1.有初始值(通常都可以显然可见)
* 2.迭代收敛(确保有最终返回)
* 3.存在使迭代子均有符合定义的值(迭代子是指min[n - 1][m],min[n - 1][m - 1], min[n][m - 1]这些迭代元素,其值均要符合题意定义)的迭代顺序
*/
public class NowSisterGiftSolution {

public static int selectPresent (int[][] presentVolumn) {
// write code here
if (null == presentVolumn) {
return -1;
}
if (presentVolumn.length == 0) {
return 0;
}
int[][] min = new int[presentVolumn.length][presentVolumn[0].length];
for (int i = 0; i < presentVolumn.length; i++) {
for (int j = 0; j < presentVolumn[i].length; j++) {
int m = 0;
if (i > 0) {
m = Math.min(min[i - 1][j], j > 0 ? min[i - 1][j - 1] : Integer.MAX_VALUE);
}
if (j > 0) {
m = Math.min(min[i][j - 1], m > 0 ? m : Integer.MAX_VALUE);
}
min[i][j] = m + presentVolumn[i][j];
}
}
return min[presentVolumn.length - 1][presentVolumn[0].length - 1];
}


public static void main(String[] strings) {
int[][] a = {{1,2,3},{2,3,4}};
int s = selectPresent(a);
System.out.println(s);
}

}

 

5.总结:

无论解决什么问题,实现是术,思路才是道;整道题下来,我的术在于实现的示例程序,而关键点在于建立状态转移方程的思路,逆向推导,理清正确迭代的决策如何通过计算实现,这才是此道题的道。另外,显然,递归也是可行的实现,在此不再赘述。




posted @ 2020-06-01 00:52  StrongKit  阅读(160)  评论(0编辑  收藏  举报