求解矩阵最小路径和问题
描述:
给定一个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
1 | 4 | 9 | 18 |
---|---|---|---|
9 | 5 | 8 | 12 |
14 | 5 | 11 | 12 |
22 | 12 | 15 | 12 |
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];
}
}