计算2D网格中的帧

时间:2015-04-18 08:18:49

标签: algorithm matrix

给定由{0}和1组成的[NxM]矩阵。找到此矩阵中没有1(每个单元格为0)的方框数。固定方框的框架是一组单元,它们中的每一个是最左边,最右边,最顶部或最底部的单元之一。因此,边长为1的方框包含1个单元,边长2包含4个,边长3-8个单元,边长4-12个单元。

大小为4的示例框架是:

0000
0  0
0  0
0000

我们需要计算仅由0组成的方框数。

示例让N=3M=4和矩阵为:

0100
0100
0000

然后答案是12,因为有10个一个大小的帧和2个两个大小的帧。

主要问题是N,M可以达到1 ≤ NM ≤ 2000。因此需要 O(N^2) 方法。

3 个答案:

答案 0 :(得分:3)

每个框架可以等同于一对矩阵的元素 - 相对的角。假设左上和右下。它们必须在对角线上,显而易见。首先请注意,如果是例如。 ((1;1);(5;5))是我们的框架,元素(1;1)(5;5)必须为null。此外,从(1;1)向右和向下至少有四个空值。与(5;5)的左侧和上侧相同。因此,第一个想法是计算每个元素x最小的空值向下和向左与自己(线性时间)。

如果我没有犯错误,那就是:

-->(x;y) = (min(right, down); min(left,upward))

00000    (5;1)(1;1)(1;1)(2;1)(1;1)
01101    (1;1)(0;0)(0;0)(1;1)(0;0)
01001--->(1;1)(0;0)(2;1)(1;2)(0;0)
00000    (2;1)(1;1)(1;2)(1;4)(1;1)
01110    (1;1)(0;0)(0;0)(0;0)(1;1)

第二个想法:分别从左上角到右下角分析每条对角线。

  1. (1; 1)
  2. (2; 1)(0; 0)
  3. (1; 1)(1; 1)(0; 0)
  4. 依旧......
  5. 你需要一些结构Q对,这将允许你:

    • 删除后续元素小于... O(lg n)
    • 计算前导大于... O(lg n)
    • 的元素
    • 添加对。 O(lg n)

    将全局结果设置为null。 每个对角线的算法很容易。取空​​Q.迭代以下元素i = 0,1,2,...。每个人:

    • 从Q元素中删除,其后继元素小于i。 (它可能只是最小继任者的元素。)
    • 如果实际元素不是(0; 0):
      • 推送对,前任:i和后继:具有女巫实际元素的最后一个元素的数量可以配对。它是i+x_i-1,其中x_i是实际元素的min(right, down)
      • 在Q中计算元素的前导大于i-y_i的元素。这些是可以与实际元素配对的元素。将该号码添加到' global'结果

    在全球结果中,您有答案。它是O(NM log N)算法,我不确定,如果你能更快地完成它。


    对角线的例子。我们有table =((5; 1),(0; 0),(2; 1),(1; 4),(1; 1))来分析。

    Generally for element:
       Current element: (x;y); i=i           // O(1)
       Q.erase_smaller_than(i)              // O(lg N)
       if (x;y) == (0;0) :                  // O(1)
            skip element
       Q.emplace(i, i+x-1)                  // O(lg N)
       result += Q.count_bigger_than(i-y)   // O(lg N)
    
    
    For diagonal example:
    
    0. Q = {}
       result = 0
       for element in ((5;1),(0;0),(2;1),(1;4),(1;1))
    
    1. Current element: (5;1); i = 0
       Q.erase_smaller_than(i)
       Q.emplace(i, i+5-1) // (0; 4)
       temp = Q.count_bigger(i-1) //taking only predecessor
       // bigger than -1, 1. element (frame with only one element)
       result += temp // result = 1
    
    2. Current element: (0;0); i = 1
       Q.erase_smaller_than(i) //nothing changed
       (0;0) element, skip
    
    3. Current element: (2;1); i = 2
       Q.erase_smaller_than(i) //nothing changed, Q = {(0;4)}
       Q.emplace(i, i+2-1) // (2;4)
       temp = Q.count_bigger(i-1) // only current element
       result += temp // result = 2
    
    4. Current element (1;4); i = 3
       Q.erase_smaller_than(i) //Q = {(0;4)(2;4)}
       Q.emplace(i; i+1-1) // (3; 3)
       temp = Q.count_bigger(i-4) //all three elements from Q
       result += temp // result = 5\
    
    5. Current element (1;1); i = 4
       Q.erase_smaller_than(i) // Q = {}
       Q.emplace(i;i+1-1) // (4;4)
       temp = Q.count_bigger(i-1) // only current element
       result += 1
    
    6. End of loop. Print "On main diagonal $result frames have corners.".
       Continue that algorithm for next diagonal lines.
    

答案 1 :(得分:1)

我用c#中的代码解释我的算法:

static void Main(string[] args)
{
    int[,] ar = new int[,] { {0,1,0,0}, 
                             {0,1,0,0}, 
                             {0,0,0,0} };

    int count = 0; // Count of square matrices
    int sum = 0;   // A temporary variable for checking validation of a square matrices

    int max = 0;   // Max size of square matrices for each point

    for (int i = 0; i < ar.GetLength(0) ; i++)
    {
        for (int j = 0; j < ar.GetLength(1); j++)
        {
            if (ar[i, j] == 0)
            {
                //calculate maximum size of square Matrices
                max = ar.GetLength(0) - i;
                if (max > ar.GetLength(1) - j)
                    max = ar.GetLength(1) - j;

                //Search kxk square matrice
                for (int k = 0; k < max; k++)
                {
                    sum = 0;
                    // Search Borders
                    for (int l = 1; l <= k; l++)
                    {
                        sum += ar[i + l, j];
                        sum += ar[i, j + l];
                        sum += ar[i + l, j + k];
                        sum += ar[i + k, j + l];
                        if (sum > 0)
                            break;
                    }
                    sum += ar[i + k, j + k];

                    if (sum == 0)
                        count++;
                }
            }
        }
    }

    Console.WriteLine("{0}", count.ToString());
    Console.ReadKey();
}

我使用sum变量来确定所有边界点都是0。

答案 2 :(得分:0)

一个框架总是左上角0。因此,您可以遍历矩阵(对于N和M内部),并且在每次迭代中计算左上角元素为0的所有帧。在您的示例中:

0100
0100
0000
  1. 对于N=1M=1,您可以找到1帧。
  2. 下一步是N=1M=2。您可以找到0框架。
  3. 对于N=1M=3,您可以找到2
  4. 等等......