首页 > 试题广场 >

矩阵动态规划

[编程题]矩阵动态规划
  • 热度指数:617 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
     现有一个地图,由横线与竖线组成(参考围棋棋盘),且两点之间有行走距离起点为左上角,终点为右下角在地图上,每次行走只能沿线移动到临近的点,并累加路径计算一个人从地图的起点走到终点的最小路径为多少。

输入描述:
m*n地图表示如下:

3
3
1 3 4
2 1 2
4 3 1

其中m=3,n=3 表示3*3的矩阵

行走路径为:下>右>右>下


输出描述:
路径总长:1+2+1+2+1=7
示例1

输入

1
2
1 2

输出

3
示例2

输入

2
3
9 8 6
2 3 7

输出

21

备注:
地图参数为:
1
2

1 2

m=1,n=2,表示1*2的矩阵,最短距离是左>右
分析:
这个题隐含的设定是:当前节点只能 往下 或者 往右 走。因为如果可以 往左 或者 往上 的话,那就死循环了,例如当前位置  [i][j], 先 往右 得到  [i+1][j], 再 往左 得到 [i][j] ..... 死循环了。往上类似,不做累述。

实现:
笔者用了三种方法实现,大家可以一起探讨:
import java.util.Scanner;

public class Main {
    // 分析: 从左往右的尝试
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int row = in.nextInt();
        int col  = in.nextInt();
        int[][] array = new int[row][col];
        in.nextLine();
        for (int i = 0; i < row; i++) {
            String[] numbers = in.nextLine().split(" ");
            for (int j = 0; j < col; j++) {
                array[i][j] = Integer.parseInt(numbers[j]);
            }
        }
        System.out.println(process1(array, row, col, 0, 0));
        System.out.println(process2(array));
        System.out.println(process3(array));
    }

    // 暴力递归.   返回值表示从当前位置出发,到结束时,最小的路径.
    private static int process1(int[][] array, int row, int col, int i, int j) {
        if (i == row - 1 && j == col - 1) { // 终止位置
            return array[i][j];
        }
        if (i == row - 1) { // 最后一行,非终止位置
            return array[i][j] + process1(array, row, col, i, j + 1);
        }
        if (j == col - 1) { // 最后一列,非终止位置
            return array[i][j] + process1(array, row, col, i + 1, j);
        }
        // 中间,取朝右或者朝下中较小值,在加上当前值
        return Math.min(process1(array, row, col, i, j + 1), process1(array, row, col, i + 1, j)) + array[i][j];
    }

    // 记忆化搜索,动态规划
    private static int process2(int[][] array) {
        int row = array.length;
        int col = array[0].length;
        int[][] dp = new int[row][col];
        dp[row - 1][col - 1] = array[row - 1][col - 1];
        for (int j = col - 2; j >= 0; j--) {
            dp[row - 1][j] = array[row - 1][j] + dp[row - 1][j + 1];
        }
        for (int i = row - 2; i >= 0; i--) {
            dp[i][col - 1] = array[i][col - 1] + dp[i + 1][col - 1];
        }
        for (int i = row - 2; i >= 0; i--) {
            for (int j = col - 2; j >= 0; j--) {
                dp[i][j] = Math.min(dp[i][j + 1], dp[i + 1][j]) + array[i][j];
            }
        }
        return dp[0][0];
    }

    // 直接修改原数组,从右往左,由下到上推结果. 动态规划
    private static int process3(int[][] array) {
        int row = array.length;
        int col = array[0].length;
        for (int j = col - 2; j >= 0; j--) {
            array[row - 1][j] += array[row - 1][j + 1];
        }
        for (int i = row - 2; i >= 0; i--) {
            array[i][col - 1] += array[i + 1][col - 1];
        }
        for (int i = row - 2; i >= 0; i--) {
            for (int j = col - 2; j >= 0; j--) {
                array[i][j] += Math.min(array[i][j + 1], array[i + 1][j]);
            }
        }
        return array[0][0];
    }
}



发表于 2023-05-10 18:43:13 回复(1)