/* * The MIT License (MIT) * * Copyright © 2022 xrv * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package io.github.ehlxr.algorithm.dp; /** * 假设我们有一个 n 乘以 n 的矩阵 w [n][n]。矩阵存储的都是正整数。棋子起始位置在左上角,终止位置在右下角。 * 我们将棋子从左上角移动到右下角。每次只能向右或者向下移动一位。从左上角到右下角,会有很多不同的路径可以走。 * 我们把每条路径经过的数字加起来看作路径的长度。那从左上角移动到右下角的最短路径长度是多少呢? * * @author ehlxr * @since 2022-03-05 16:46. */ public class MinDist { private final int[][] matrix = {{1, 3, 5, 9}, {2, 1, 3, 4}, {5, 2, 6, 7}, {6, 8, 4, 3}}; private final int[][] mem = new int[4][4]; private int minDist = Integer.MAX_VALUE; // 全局变量或者成员变量 /** * 动态规划:状态转移表法 */ public int minDistDP(int[][] matrix, int n) { int[][] states = new int[n][n]; int sum = 0; for (int j = 0; j < n; ++j) { // 初始化states的第一行数据 sum += matrix[0][j]; states[0][j] = sum; } sum = 0; for (int i = 0; i < n; ++i) { // 初始化states的第一列数据 sum += matrix[i][0]; states[i][0] = sum; } for (int i = 1; i < n; ++i) { for (int j = 1; j < n; ++j) { states[i][j] = matrix[i][j] + Math.min(states[i][j - 1], states[i - 1][j]); } } return states[n - 1][n - 1]; } /** * 动态规划:状态转移方程法 */ public int minDist(int i, int j) { // 调用minDist(n-1, n-1); if (i == 0 && j == 0) { return matrix[0][0]; } // 备忘录,如果计算过,即有数字存在,则直接返回 if (mem[i][j] > 0) { return mem[i][j]; } int minLeft = Integer.MAX_VALUE; if (j - 1 >= 0) { minLeft = minDist(i, j - 1); } int minUp = Integer.MAX_VALUE; if (i - 1 >= 0) { minUp = minDist(i - 1, j); } int currMinDist = matrix[i][j] + Math.min(minLeft, minUp); mem[i][j] = currMinDist; return currMinDist; } /** * 回溯方式 */ public void minDistBacktracing(int i, int j, int dist, int[][] w, int n) { // 到达了n-1, n-1这个位置了,这里看着有点奇怪哈,你自己举个例子看下 if (i == n && j == n) { if (dist < minDist) { minDist = dist; } return; } if (i < n) { // 往下走,更新i=i+1, j=j minDistBacktracing(i + 1, j, dist + w[i][j], w, n); } if (j < n) { // 往右走,更新i=i, j=j+1 minDistBacktracing(i, j + 1, dist + w[i][j], w, n); } } }