当前位置: 首页 > news >正文

算法: 动态规划,二维矩阵代价最值进阶版 两条行进路径,一次相交,求解最大代价

2D矩阵进阶问题: 求解两人最大总卡路里消耗量

问题:

现存一个2D矩阵 N x M , 给定一个二维数组 calorie[N][M] 表示访问到坐标 (N, M)消耗的卡路里值。现在有两个人,一个人(男孩)起点为 (1, 1),另一人(女孩)起点为 (N, 1),他们分别要到终点1 (N, M) 和终点2 (1, M)。男孩一步只能往右或者往下行进,女孩一步只能往右或者往上行进。且在二者行进路径上,只允许有一个相遇点,且在总卡路里消耗中,这个相遇点的卡路里不被加到男孩或女孩的消耗量中,求解最大卡路里消耗量总数。

在这里插入图片描述

问题分析:

乍一看,这个问题比我们之前三个问题复杂多了。但是除开各种条件,本质上还是一个求解消耗最值的问题。接下来我们重点分析文中的关键限制条件:二者行进路径上只允许有一个相遇点。

假设相遇点为(i, j)

首先,男孩通过这个相遇点前后的可能路径为:

  • (i-1, j) --> (i, j) --> (i+1, j)
  • (i-1, j) --> (i, j) --> (i, j+1)
  • (i, j-1) --> (i, j) --> (i, j+1)
  • (i, j-1) --> (i, j) --> (i+1, j)

类似的,女孩通过这个相遇点前后的可能路径为:

  • (i+1, j) --> (i, j) --> (i-1, j)
  • (i+1, j) --> (i, j) --> (i, j+1)
  • (i, j-1) --> (i, j) --> (i-1, j)
  • (i, j-1) --> (i, j) --> (i, j+1)

由于除了相遇点(i, j)之外不能有其他相同的行进坐标,因此,二者通过相遇点前后的可能路径只可能为:

  • 男孩:(i-1, j) --> (i, j) --> (i+1, j) ,女孩:(i, j-1) --> (i, j) --> (i, j+1)
  • 男孩:(i, j-1) --> (i, j) --> (i, j+1) ,女孩:(i+1, j) --> (i, j) --> (i-1, j)

在这篇博文中,求解出了到达某一坐标的代价最值算法,那可不可以完全套用这个算法,查出条件下的最值呢?答案是不可以。因为这个算法得出的最值数组是从起点(0, 0) 到目标坐标(N, M)的代价最值。它并没有限制在路径中必须经过相遇点(i, j)。所以,需要把当前问题分隔成更小的问题

二者的行进路径被分四个部分:

  • 男孩从起点到达相遇点前
  • 男孩离开相遇点,到达终点
  • 女孩从起点到达相遇点前
  • 女孩离开相遇点,到达终点

只需要求出

  • 男孩从(1, 1)到 (i-1, j)、(i+1, j)到(N, M)的代价最值与女孩从(N, 1)到 (i, j-1)、(i, j+1)到(1, M)的代价最值之和
  • 男孩从(1, 1)到 (i, j-1)、(i, j+1)到(N, M)的代价最值与女孩从(N, 1)到 (i+1, j)、(i-1, j)到(1, M)的代价最值之和

再将二者比较,取最值,即得答案。

即,需要求得从男孩与女孩起点到相遇点的路径代价最值数组,以及相遇点到终点的路径代价最值数组,共四个代价数组。

还有一些小细节:

  • 根据 i-1, i+1, j-1, j+1需落在坐标区间内,可得相遇点(i, j) 2 <= i <= N-1, 2 <= j <= M-1
算法如下:
/**
 * 
 * @param {int[N][M]} calorie
 * @param {int} N
 * @param {int} M
 */
var calories = function(calorie, N, M) {
  var totalCalories = 0
  var BoyStartToMeet = construct(N, M)
  var BoyEndToMeet = construct(N,M)
  var GirlStartToMeet = construct(N, M)
  var GirlEndToMeet = construct(N, M)
  for (let i = 1; i <= N; i++) {
    for (let j = 1; j <= M; j++) {
      BoyStartToMeet[i][j] = Math.max(BoyStartToMeet[i - 1][j], BoyStartToMeet[i][j - 1]) + calorie[i][j]
    }
  }
  for (let i = N; i >= 1; i--) {
    for (let j = M; j >= 1; j--) {
      BoyEndToMeet[i][j] = Math.max(BoyEndToMeet[i + 1][j], BoyStartToMeet[i][j + 1]) + calorie[i][j]
    }
  }
  for (let i = N; i <= 1; i++) {
    for (let j = 1; j <= M; j++) {
      GirlStartToMeet[i][j] = Math.max(BoyStartToMeet[i + 1][j], BoyStartToMeet[i][j - 1]) + calorie[i][j]
    }
  }
  for (let i = 1; i <= N; i++) {
    for (let j = M; j >= 1; j--) {
      GirlEndToMeet[i][j] = Math.max(BoyEndToMeet[i - 1][j], BoyStartToMeet[i][j + 1]) + calorie[i][j]
    }
  }
  for (let i = 2; i < N; i++) {
    for (let j = 2; j < M; j++) {
      var opt1 = BoyStartToMeet[i][j - 1] + BoyEndToMeet[i][j + 1] + GirlStartToMeet[i + 1][j] + GirlEndToMeet[i - 1][j]
      var opt2 = BoyStartToMeet[i - 1][j] + BoyEndToMeet[i + 1][j] + GirlStartToMeet[i][j - 1] + GirlEndToMeet[i][j + 1]
      totalCalories = Math.max(totalCalories,Math.max(opt1,opt2))
    }
  }

  return totalCalories
}

var construct = function(N, M) {
  var c = new Array()
  for (let i = 0; i < N; i++) {
    c[i] = new Array()
    for (let j = 0; j < M; j++) {
      c[i][j] = 0          
    }
  }
  return c
}

如果你对题解中得代码有疑问、不解,欢迎评论,我会尽力为你解答。

相关文章:

  • Programming Languages And Lambda calculi 1.1 定义集合
  • 算法: 动态规划 编辑距离 Edit Distance / Levenshtein Distance
  • 【Salesforce】【Apex】Trigger中不通过soql查询记录类型的开发名称
  • 【Programming Languages And Lambda calculi】 1.2 ~ 1.3 关系、赋值与关系
  • 【Programming Languages And Lambda calculi】 1.4 有向赋值
  • 【算法】 动态规划 基础题库 1-7 python实现
  • 【Programming Languages And Lambda calculi】 1.5 ~ 1.7 上下文规约 赋值函数 符号摘要
  • 【Programming Languages And Lambda calculi】第二章 结构归纳法 2.1 基础
  • 【Programming Languages And Lambda calculi】2.2 ~ 2.3 定义中的省略,证明树中的归纳
  • 【Programming Languages And Lambda calculi】2.4 ~ 2.5 多重结构,更多的定义与证明 第二章结束
  • 【Programming Languages And Lambda calculi】第三章 求值一致性 Church-Rosser 关系 (本章仅一节)
  • 【Programming Languages And Lambda calculi】第四章 Lambda演算 / Lambda表达式 4.1 演算中的函数 柯里化
  • 【Programming Languages And Lambda calculi】4.2 Lambda演算的语法与约化
  • 【Programming Languages And Lambda calculi】4.3 Lambda 表达式中给布尔值编码
  • 【Programming Languages And Lambda calculi】4.4 Lambda 表达式 对值编码
  • 30天自制操作系统-2
  • Asm.js的简单介绍
  • CentOS7 安装JDK
  • Codepen 每日精选(2018-3-25)
  • Gradle 5.0 正式版发布
  • JS基础篇--通过JS生成由字母与数字组合的随机字符串
  • js如何打印object对象
  • Logstash 参考指南(目录)
  • nodejs:开发并发布一个nodejs包
  • SpiderData 2019年2月23日 DApp数据排行榜
  • UMLCHINA 首席专家潘加宇鼎力推荐
  • windows下使用nginx调试简介
  • 初探 Vue 生命周期和钩子函数
  • 开源地图数据可视化库——mapnik
  • 我从编程教室毕业
  • ​一文看懂数据清洗:缺失值、异常值和重复值的处理
  • #Linux(帮助手册)
  • (23)Linux的软硬连接
  • (C语言)输入一个序列,判断是否为奇偶交叉数
  • (动态规划)5. 最长回文子串 java解决
  • (二)Linux——Linux常用指令
  • (附源码)基于ssm的模具配件账单管理系统 毕业设计 081848
  • (转)Sublime Text3配置Lua运行环境
  • (转)winform之ListView
  • ***微信公众号支付+微信H5支付+微信扫码支付+小程序支付+APP微信支付解决方案总结...
  • .NET Core 控制台程序读 appsettings.json 、注依赖、配日志、设 IOptions
  • .Net8 Blazor 尝鲜
  • .net下简单快捷的数值高低位切换
  • /usr/bin/env: node: No such file or directory
  • /var/log/cvslog 太大
  • @Autowired和@Resource装配
  • @staticmethod和@classmethod的作用与区别
  • [ CTF ]【天格】战队WriteUp- 2022年第三届“网鼎杯”网络安全大赛(青龙组)
  • [2015][note]基于薄向列液晶层的可调谐THz fishnet超材料快速开关——
  • [Android Studio] 开发Java 程序
  • [BUUCTF]-Reverse:reverse3解析
  • [C#]获取指定文件夹下的所有文件名(递归)
  • [CDOJ 838]母仪天下 【线段树手速练习 15分钟内敲完算合格】
  • [GYCTF2020]Ez_Express
  • [HCTF 2018]WarmUp (代码审计)