矩阵的左上象限的最大和,可以通过反转行和列来形成

时间:2016-10-23 17:07:18

标签: c# algorithm data-structures time-complexity

我正在处理一个HackerRank问题,该问题是在反转行和列之后找到2N x 2N矩阵的左上象限中元素的最大总和。例如,如果矩阵是

M = [
  112  42   83   119
  56   125  56   49
  15   78   101  43
  62   98   114  108
];

然后在获得矩阵后,可以通过反转行和列形成的最大总和为119 + 114 + 56 + 125 = 414

M' = [
   119  114  42   112
   56   125  101  49
   15   78   56   43
   62   98   83   108
];

从反转第2列然后第0行。

我还没有找到一个简单的解决方案,但我提出了一些可能有用的事实:

  • 可以从反转行和列中获取任何配置。因此,答案不能简单地对所有元素进行排序,并对它们的顶部NxN求和。
  • 此外,无法将任何1个元素移动到任何其他位置。例如,要移动的元素(N-1,N-1)的唯一可能位置是(0,N-1),(N-1,0),(0,0)。
  • 需要1行反转才能获得从右上或左下象限到左上象限的元素,并且需要2次反转才能获得从右下象限到左上象限的元素。
  • 不可能提出一个解决方案,只需查看左上象限中的每个元素,并检查它是否可以被可以在其中移动的元素范围中的更大元素替换#39; s位置(例如M[0,1]=42可以替换为M[0,2]=83M[3,2]=114M[3,1]=98),因为您还必须考虑在此过程中拖动的其他元素。

除了这些事实,我想不出有什么能帮助我构建一个简单的解决方案。我有什么明显的事实吗?昨晚我熬夜思考这个问题。 :)

2 个答案:

答案 0 :(得分:1)

让我们开始观察元素(N - 1, N - 1)只能位于(0, 0)(N - 1, 0)(0, N - 1)位置的事实。

  • 考虑一个(r, c)元素。可以观察到它只能处于以下四个位置之一:(r, c), (N - r - 1, c), (r, N - c - 1)(N - 1 - r, N - 1 - c)

  • 可以证明总是有一系列操作将位于上述矩形顶点的四个数字中最大的一个放在左上象限而不改变其余部分(以证明它) ,人们可以只考虑所有情况并提供一个明确的构造来完成它。它很长但很简单,所以我不会在这里发布。)

  • 这两个观察结果给出了以下解决方案:

    int sum = 0;
    for (int i = 0; i < n / 2; i++)
        for (int j = 0; j < n / 2; j++)
            sum += max(a[i][j], a[i][n - j - 1], a[n - i - 1][j], a[n - i - 1][n - j - 1]); 
    

答案 1 :(得分:1)

如果不考虑捷径,总是可以委派。不仅是stackoverflow用户,还有CPU。即蛮力搜索。 蛮力适用于这个小矩阵 - 假设深度为4已经绰绰有余,并且树的分支因子是let data = let values = [| 112; 42 ; 83; 119; 56 ; 125; 56; 49; 15 ; 78 ; 101; 43; 62 ; 98 ; 114; 108 |] Array2D.init 4 4 (fun r c -> values.[4 * r + c]) let upperQuadrantSum (m : int[,]) = [ for r in 0..1 do for c in 0..1 do yield (r,c) ] |> List.sumBy (fun (r,c) -> m.[r,c]) let reverseRow row (m : int[,]) = Array2D.init 4 4 (fun r c -> if r = row then m.[r,3-c] else m.[r,c]) let reverseCol col (m : int[,]) = Array2D.init 4 4 (fun r c -> if c = col then m.[3-r,c] else m.[r,c]) let possibleActions = [ reverseRow 0; reverseRow 1; reverseRow 2; reverseRow 3; reverseCol 0; reverseCol 1; reverseCol 2; reverseCol 3; ] let maximize metric maxDepth m0 = let rec search depth m = let value = metric m if depth = maxDepth then value else possibleActions |> List.map (fun a -> let m1 = a m in max (metric m1) (search (depth+1) m1)) |> List.max |> fun msearch -> max value msearch search 0 m0 let solve = maximize upperQuadrantSum ,其中N分别是数字或行和列。 (N行可以反转,N列。)

这里,对于问题中的4x4矩阵,各自的解决方案:

let inline solve1 m = 
    let n = Array2D.length1 m
    let candidates r c =
        [ r,c ; n-1-r,c ; r,n-1-c ; n-1-r,n-1-c ]
    [
        for r in 0..n/2-1 do
            for c in 0..n/2-1 do
                yield (candidates r c |> List.map (fun (r,c) -> m.[r,c]) |> List.max)
    ] |> List.sum

solve1 data

在fsi中,发出:

  

解决7个数据;;
  val it:int = 414

当然,正如其他答案所述,一旦想到优化, 很高兴有蛮力解决方案,以验证两者产生 同样的结果:

 #include "opencv2/opencv.hpp"

很抱歉没有用C#编写代码,但.fsx文件和fsi比创建另一个C#应用程序容易得多......