【问题标题】:Find minimum sum of elements in a matrix查找矩阵中元素的最小总和
【发布时间】:2020-02-06 00:19:12
【问题描述】:

给定一个矩阵,找出元素的最小总和,使得从每一行中选择元素,并且相邻元素不应来自同一列。假设矩阵只有 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。我认为动态编程将是解决此问题的方法,但我不确定如何构造 mem 部分。如何用动态规划实际解决这个问题?提前致谢!

【问题讨论】:

  • 这是一个问题陈述,但您的问题是什么?
  • 这是动态规划、回溯或任何其他可用空间遍历方法的直接应用。请发布您的代码和完整的问题说明;在 Stack Overflow 上通常不接受在没有预期解决方案尝试的情况下发布作业(或自行分配的问题)。
  • @Prune 感谢您的通知。问题已更新!
  • 你在哪里卡住了 DP 部分?您的状态信息包括到目前为止的总和、当前行和选择的最后一列。您还需要遍历每一行的 all 合法选择(第一行 3 个,之后的行 2 个)。
  • @Prune 我无法识别递归结构。我不太确定我应该如何构建内存。

标签: java algorithm matrix dynamic-programming minimization


【解决方案1】:

是的,您需要识别您在其中一个 cmets 中指定的递归结构。

您可以识别如下: 假设您当前在一行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

【讨论】:

    【解决方案2】:

    非常感谢@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 指定的所有上述测试用例,它有效。

    【讨论】:

      猜你喜欢
      • 2016-02-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多