查找矩阵中元素的最小和

时间:2020-02-06 00:19:12

标签: java algorithm matrix dynamic-programming minimization

给出一个矩阵,找到元素的最小总和,以便从每一行中选择元素,并且相邻元素不应来自同一列。假设矩阵只有3列。

example 1:
[[1, 2, 3], 

 [1, 2, 3], 

 [3, 3, 1]]

minimum sum = 1 + 2 + 1 = 4  // matrix[0][0] + matrix[1][1] + matrix[2][2] or matrix[0][1] + matrix[1][0] + matrix[2][2]

example 2:
[[1, 100, 1], 

 [2, 99, 30],

 [100, 12, 13]]

minimum sum = 1 + 2 + 12 = 15 // matrix[0][2] + matrix[1][0] + matrix[2][1]

example 3:
[[1, 2, 3], 

 [2, 5, 4],

 [2, 3, 1],

 [1, 6, 3]]

minimum sum = 2 + 2 + 1 + 1 = 6 // matrix[0][1] + matrix[1][0] + matrix[2][2] + matrix[3][0]

这是我的代码:

    public static int minCost(List<List<Integer>> matrix) {
        // Write your code here
        int rows = matrix.size();

        int[] cost = findMin(matrix.get(0), -1);
        int total = cost[0];

        for (int i = 1; i < rows; i++){
            List<Integer> row = matrix.get(i);
            cost = findMin(row, cost[1]);
            total += cost[0];
        }
        return total;
    }

    private static int[] findMin(List<Integer> row, int col){
        int[] ans = new int[2];
        int min = Integer.MAX_VALUE;
        for (int i = 0; i < row.size(); i++) {
            if (i == col){
                continue;
            }
            if (row.get(i) < min) {
                min = row.get(i);
                ans[0] = min;
                ans[1] = i;
            }
        }
        return ans;
    }

我最初是用Greedy来解决这个问题的,它是在一行中找到最小的元素,并且该元素的列与前一个元素不同。

此方法不满足示例2和3。我认为动态编程将是解决此问题的方法,但我不确定如何构造内存部分。如何用动态编程实际解决这个问题?预先感谢!

2 个答案:

答案 0 :(得分:1)

是的,您需要像在注释之一中指定的那样标识递归结构。

您可以确定以下内容: 假设您当前在row行上,并且您选择的上一列是prevcol,那么您需要选择一个不在上一列中的值,然后递归其余行并获得最小值所有这些值,即每次您选择不是上一列的列,并通过指定选择的上一列是您刚选择的那一列来递归其余行时。

请查看此递归方程以了解更多信息:

f( arr, row, prevcol ) = minimum of ( for all col not equal to prevcol ( arr[row][col] + f( arr, row + 1, col ) )

您将了解如何指定在调用f(arr, row +1, col )中选择的下一行和上一列?

基本条件是如果row == arr.length,即没有剩余行,则结果为0

您会记住从rowprevcol的每种组合获得的值

Java代码为:

private static int f( int[][] arr, int row, int prevCol ) {
    if ( row == arr.length ) return 0;

    int C = arr[row].length;
    if ( dp[row][prevCol+1] != Integer.MAX_VALUE ) return dp[row][prevCol+1];
    int res = Integer.MAX_VALUE;
    for ( int j = 0; j < C; j++ ) {
      if ( j != prevCol ) {
        int val = arr[row][j] + f ( arr, row + 1, j );
        res = Math.min ( res, val );
      }
    }
    dp[row][prevCol+1] = res;
    return res;
  }

您需要像这样实例化dp数组:

dp = new int[arr.length][arr[0].length+1];
for ( int[] r : dp ) Arrays.fill(r, Integer.MAX_VALUE);

,然后调用以下函数: f( arr, 0, -1 ),其中0是起始row-1prevcol。由于prevcol-1开头,因此您需要将值存储在dp[row][prevcol+1]

第三个示例的答案是6而不是9

row = 0, col = 1 : 2
row = 1, col = 0 : 2
row = 2, col = 2 : 1
row = 3, col = 0 : 1
2 + 2 + 1 + 1 = 6

答案 1 :(得分:1)

非常感谢@SomeDude 这是我对python的相同实现。

import math
def mincost(arr,row,prevcol,n,k):
    if row == len(arr):
        return 0
    C = len(arr[row])
    dp = [[math.inf for x in range(k+1)] for y in range(n)]
    if dp[row][prevcol+1] != math.inf:
        return dp[row][prevcol+1]
    res = math.inf
    for j in range(C):
        if j != prevcol:
            val = arr[row][j] + mincost(arr,row+1,j,n,k)
            res = min(res,val)
    dp[row][prevcol+1] = res
    return res

我检查了@bonus指定的所有上述测试用例,它可以工作。

相关问题