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


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

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

    正题:

    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.总结:

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

    
    


  • 相关阅读:
    CF1221D Make The Fence Great Again
    HDU.1536.S-Nim(博弈论 Nim)
    HDU.1848.Fibonacci again and again(博弈论 Nim)
    POJ.1704.Georgia and Bob(博弈论 Nim)
    洛谷.2197.nim游戏(博弈论 Nim)
    博弈论基础——巴什博弈
    SPOJ.104.Highways([模板]Matrix Tree定理 生成树计数)
    BZOJ.4289.PA2012 Tax(思路 Dijkstra)
    BZOJ.4753.[JSOI2016]最佳团体(01分数规划 树形背包DP)
    图论
  • 原文地址:https://www.cnblogs.com/kentkit/p/sisterpresent.html
Copyright © 2020-2023  润新知