求解矩阵最小路径和问题 动态规划

求解矩阵最小路径和问题

描述:

给定一个m行n列的矩阵,从左上角开始每次只能向右或者向下移动,最后到达右下角的位置,路径上的所有数字累加起来作为这条路径的路径和。求所有路径和中最小路径和。

输入格式:

首先输入行数m及列数n,接下来输入m行,每行n个数。

输出格式:

输出第一行为最小路径(假定测试数据中的最小路径唯一),第2行为最小路径和。

输入样例:

4 4
1 3 5 9
8 1 3 4
5 0 6 1
8 8 4 0

输出样例:

1 3 1 0 6 1 0
12

14918
95812
1451112
22121512
import java.util.Scanner;
@SuppressWarnings("all")
public class Matrix_minimum_path_sum_problem {// 求解矩阵最小路径和问题 动态规划 140 运行超时
    public static void main(String args[]){
        int m,n;
        Scanner scanner = new Scanner(System.in);
        m = scanner.nextInt();//行
        n = scanner.nextInt();//列
        int [][]a = new int[m][n];//表示矩阵
        int []path = new int[m + n - 1];//三角形两边之和必定大于第三边 故设路径最长为 m + n - 1
        for(int i = 0;i < m;i++){
            for(int j = 0;j < n;j++){
                a[i][j] = scanner.nextInt();
            }
        }
        int [][]dp = new int[m][n];//表示到达i,j位置最优解 dp[i][j] = mix(dp[i - 1][j],dp[i][j - 1]) + a[i][j]
        dp[0][0] = a[0][0];//特殊位置,直接赋值
        for(int i = 1;i < m;i++){//初始化第一行
            dp[i][0] = dp[i - 1][0] + a[i][0];
        }
        for(int j = 1;j < n;j++){//初始化第一列
            dp[0][j] = dp[0][j - 1] + a[0][j];
        }
        for(int i = 1;i < m;i++){//dp[i][j]表示从左上角a[i][j]到i,j位置的最优权值
            for(int j = 1;j < n;j++){
                dp[i][j] = Math.min(dp[i - 1][j],dp[i][j - 1]) + a[i][j];
                //                 dp[i][j] = (dp[i - 1][j] < dp[i][j - 1])?dp[i - 1][j] + a[i][j]:dp[i][j - 1] + a[i][j];
            }
        }
        int i = m - 1,j = n - 1;
        //从右下角到左上角
        path[0] = a[0][0];
        path[n + m - 2] = a[m - 1][n - 1];
        for(int k = 1;k < m + n - 2;k++){
            if(dp[i - 1][j] < dp[i][j - 1]){//向上移动
                path[m + n - 2 - k] = a[i - 1][j];
                i = i - 1;
            }
            else {//向左移动
                path[m + n - 2 - k] = a[i][j - 1];
                j = j - 1;
            }
        }
        for(int x = 0;x < m + n - 1;x++){//输出路径
            System.out.printf("%d ",path[x]);
        }        
        System.out.println();
        System.out.print(dp[m - 1][n - 1]);//输出最小路径和
    }
}
import java.util.Scanner;
@SuppressWarnings("all")
public class Matrix_minimum_path_sum_problem_Space_compression {//矩阵最小路径和及路径 动态规划 空间压缩 此解法较难,各位看不懂就别浪费时间了
    public static void main(String args[]){
        int m,n;
        Scanner scanner = new Scanner(System.in);
        m = scanner.nextInt();//行
        n = scanner.nextInt();//列
        int [][]a = new int[m][n];//表示矩阵
        for(int i = 0;i < m;i++){
            for(int j = 0;j < n;j++){
                a[i][j] = scanner.nextInt();
            }
        }
        System.out.print(minPathSum(a));
    }
    public static int minPathSum(int [][] m) {

        if(m == null || m.length == 0 || m[0] == null || m[0].length == 0){//判断特殊情况
            return 0;
        }

        int[] path = new int[2];
        int more = Math.max(m.length, m[0].length);//矩阵最长的边
        int less = Math.min(m.length, m[0].length);//矩阵最短的边
        boolean rowmore = more == m.length;//判断矩阵最长的边是不是行
        int[] dp = new int[less];//最短的边作为路径 表示到达i j 这个点的最优路径和
        dp[0] = m[0][0];
        path[1] = m[0][0];//path[0]表示在行或列之中的第几个位置 path[1]代表的是当前那个位置的数 path可以理解为路标 0-->
        for (int i = 1; i < less; i++) {
            dp[i] = dp[i - 1] + (rowmore ? m[0][i] : m[i][0]);//初始化第一行或第一列
        }
        for (int i = 1; i < more; i++) {
            dp[0] = dp[0] + (rowmore ? m[i][0] : m[0][i]);//初始化 边 或 行 的第一个数
            //            System.out.printf("%d ",dp[0]);
            for (int j = 1; j < more; j++) {
                if (j - path[0] == 1) {//j - path[0] = 1 说明当前 j 在 path的前一个位置 意味着path可以向右或向下移动了
                    System.out.printf("%d ", path[1]);//输出当前最优path中的数
                    if (dp[j] < dp[j - 1]) {//说明向右移动
                        path[0] = path[0] + 1;
                        //                        path[1] = m[i - 1][path[0]];
                        path[1] = (rowmore?m[i - 1][path[0]]:m[path[0]][i - 1]);
                    } else {//向下移动
                        path[1] = (rowmore?m[i][path[0]]:m[path[0]][i]);
                        //                        path[1] = m[i][path[0]];
                    }
                }
                dp[j] = Math.min(dp[j - 1], dp[j]) + (rowmore ? m[i][j] : m[j][i]);//dp[j - 1]表示上一个位置向下 dp[j]表示上一个位置向右
            }
            if (path[0] == more - 1) {//表示当前路标位置已经到末尾 也就是最短行或列的末尾 差一格到右下角最后一个
                System.out.printf("%d %d \n", path[1], m[m.length - 1][m[0].length - 1]);
            }
        }
        return dp[less - 1];
    }
}

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 矩阵最小路径问题是指给定一个矩阵,从左上角出发,每次只能向右或向下走,到达右下角的最小路径和。这个问题可以使用动态规划来解决。具体来说,我们可以定义一个二维数组dp,其中dp[i][j]表示从左上角到达(i,j)位置的最小路径和。则有以下状态转移方程: dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + matrix[i][j] 其中,matrix[i][j]表示矩阵中第i行第j列的元素值。最终的答案即为dp[m-1][n-1],其中m和n分别为矩阵的行数和列数。 ### 回答2: 矩阵最小路径问题指的是在一个矩阵中,从左上角到右下角的一条路径上,求路径上所有元素值之和最小问题。这是一个典型的动态规划问题。 我们可以定义一个二维数组dp[m][n],其中dp[i][j]表示从矩阵的左上角到第i行j列的元素的最小路径和。显然,矩阵的左上角元素的最小路径和为其本身,即dp[0][0] = matrix[0][0]。 对于其他位置的元素,我们可以通过以下递推公式来求解: dp[i][j]=min(dp[i-1][j],dp[i][j-1])+matrix[i][j] 其中,dp[i-1][j]表示从左上角到dp[i-1][j]的路径最小和,dp[i][j-1]表示从左上角到dp[i][j-1]的路径最小和,matrix[i][j]表示当前位置的元素值。 最后,dp[m-1][n-1]就是从左上角到右下角的最小路径和。 具体的实现可以用两层循环来遍历矩阵,来更新dp数组。最终的时间复杂度为O(mn),空间复杂度也为O(mn)。 需要注意的是,在实际的求解过程中,为了避免dp数组中的元素被反复读取,可以在原始矩阵上进行原地修改,不需要新建一个dp数组。这样可以将空间复杂度降至O(1)。 总之,矩阵最小路径问题是一个经典的动态规划问题。通过定义dp数组,以及递推公式,可以很好地解决这个问题。在实际中,需要注意如何优化空间复杂度,以及边界条件的处理。 ### 回答3: 矩阵最小路径问题是指在一个矩阵中,从左上角走到右下角,每次只能向下或向右走,求经过的路径上数字之和的最小值。这个问题可以使用动态规划算法来解决。 首先,我们可以定义一个二维的状态数组 dp[i][j],其中 dp[i][j] 表示从左上角走到位置 (i,j) 的最小路径和。对于第一行和第一列,它们只能向右或向下走,因此它们的状态值可以直接累加。即 dp[i][0] = sum(0,0->i,0),dp[0][j] = sum(0,0->0,j)。 对于其它位置 (i,j),它们可以从其上面或左边的位置转移而来。因此,我们有如下的转移方程: dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + matrix[i][j] 其中,matrix[i][j] 表示位置 (i,j) 上的数字。 最后,矩阵最小路径和就是 dp[m-1][n-1],其中 m 和 n 分别是矩阵的行数和列数。 使用动态规划算法求解矩阵最小路径问题的时间复杂度为 O(mn),空间复杂度为 O(mn)。因此,这个算法在面对大规模矩阵时可能会产生性能问题。为了解决这个问题,我们可以使用滚动数组来减小空间复杂度,或者使用贪心算法来近似解决问题

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值