在给定的1000 x 1000阵列中存在不同的矩形。在<Figure 1>
中,显示为黄色单元格的序列“1”是矩形图案。 <Figure 1>
中矩形的最小尺寸为3 x 3,显示为绿色单元格。
矩形内应该至少有一个'0'。
但是,在这个数组中,也存在未闭合的形状或直线图案。
(数组的初始值为'0',模式表示一系列'1'。它们不重叠或相互包含。)
除了未闭合的形状或直线外,什么可能是一个有效的算法来找到阵列中的完整的整数?例如,在上图中,完整矩形的数量是3
答案 0 :(得分:21)
这很简单。如果您有n
个方块,则可以计算O(n)
中的矩形。
假设:
你需要额外的内存和输入一样大。让我们调用此visited
并使用0初始化。
让我们首先构建一个辅助函数:
is_rectangle(square s)
from s, go right while you see 1s and visited is 0
mark them as 1 in visited
if less than 3 steps
return 0
then, go down while you see 1s and visited is 0
mark them as 1 in visited
if less than 3 steps
return 0
then, go left while you see 1s and visited is 0
mark them as 1 in visited
if less than 3 steps
return 0
then, go up while you see 1s and visited is 0
mark them as 1 in visited
if then one above is not s
return 0
return 1
此功能基本上跟踪右下左上方向的1,并检查条件是否满足(长度至少为3并到达起始位置)。它也标志着访问过的广场。
关于这个函数需要注意的重要一点是,只有当初始方块是左上角时它才能正常工作。
现在,问题的解决方案很简单:
num_rectangles = 0
initialize visited to 0 (rows x columns)
for r in rows
for c in columns
if visitied[r][c] or image[r][c] == 0
continue
num_rectangles += is_rectangle(<r,c>)
return num_rectangles
以下是算法的执行方式:
1.失败(并标记)坏矩形的一部分
2.找到(并标记)一个矩形。
3.单个方格(垂直线)失败
4.单个方格(垂直线)失败
5.单个方格(垂直线)失败
6.经过许多类似的步骤,找到了下一个矩形。
7.下一个矩形
8.算法结束
答案 1 :(得分:4)
以下O(n)算法将在任何具有0/1值的2D矩阵上工作(即,允许交叉/重叠矩形,以及任意非矩形打开/关闭形状) 。我在这里使用的矩形的定义是“内部完全由0个单元格组成”(例如,如果一个矩形完全包含另一个矩形,则只能找到内部矩形;如果还要考虑包含矩形,那么可以删除每个找到的矩形并重新启动算法)。它基于观察结果,即每个0-单元格可以位于内部,最多只有一个1-矩形。
我使用的惯例是x = 0是最左边的位置而y = 0是最顶端的位置。
答案 2 :(得分:3)
如果阵列中只有矩形形状,则相当于二进制图像上的经典计算问题:只需对连接的组件应用标准算法即可。您只标记0的连接组件,并对它们进行计数。
例如,请参阅http://en.wikipedia.org/wiki/Connected-component_labeling。这种类型的算法在图像上非常简单,但需要一些内存(与输入数组大小相同,类型为short或int)。注意连接:如果选择4连接,即使缺少某些角,也会计算封闭的矩形。但该算法比使用8连接更简单。
如果你可以有更复杂的封闭形状,只需添加一个后处理:对于每个连通的组件,计算组件边界框内的像素数(如果两个数字相等,你有一个矩形)< / p>
答案 3 :(得分:2)
考虑一下。我想出了这个方法:
1)消除边缘周围的所有零 - 将其值更改为2
2)洪水填充2s周围的矩阵
这使你只剩下零点,现在可以测试它的凸度。 所以对于每个岛屿:
3)在X和Y中查找0值的范围 - 给你一个潜在的内部矩形
4)如果内部矩形包含1个OR外部矩形包含0,则填充该岛2s,因为它不是凸起的(因此不是矩形)
假设您可以找到一个好的洪水填充算法(不像我的),这应该可以有效地快速切割搜索空间。
现在代码(抱歉是C锐):
using System;
using System.Collections.Generic;
namespace Test
{
class MainClass
{
static private int [,] matrix = new int[,] {
{0,0,0,0,0,0,0,0,1,1,1,1,0,0,0},
{0,1,1,1,1,1,1,0,1,0,0,1,0,1,0},
{0,1,0,0,0,0,1,0,1,0,0,1,0,1,0},
{0,1,0,0,0,0,1,0,1,0,0,1,0,1,0},
{0,1,0,0,0,0,1,0,1,0,0,0,0,1,0},
{0,1,0,0,0,0,1,0,1,0,0,0,0,1,0},
{0,1,1,1,1,1,1,0,1,0,0,1,0,1,0},
{0,0,0,0,0,0,0,0,1,1,1,1,0,0,0},
{0,0,1,1,1,1,0,0,0,0,0,0,0,0,0},
{0,0,1,0,0,1,0,0,1,1,1,0,1,1,0},
{0,0,1,1,1,1,0,0,1,0,1,0,0,0,0},
{0,0,0,0,0,0,0,0,1,1,1,0,0,0,0}
};
static private int width = matrix.GetLength(0);
static private int height = matrix.GetLength(1);
private const int DEAD = 2;
private const int RECT = 3;
public static void Main (string[] args)
{
//width = matrix.GetLength(0);
//height = matrix.GetLength(1);
PrintMatrix ();
EliminateFromEdges (DEAD);
PrintMatrix ();
FloodFill (DEAD); // very inefficient - find a better floodfill algorithm
PrintMatrix ();
// test each island of zeros for convexness
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
if (matrix[i,j] == 0)
{
if (TestIsland(i,j) == false)
{
// eliminate this island as it is not convex
matrix[i,j] = DEAD;
FloodFill(DEAD);
PrintMatrix ();
}
else
{
// flag this rectangle as such
matrix[i,j] = RECT;
FloodFill(RECT);
PrintMatrix ();
}
}
}
}
// We're done, anything flagged as RECT can be expanded to yield the rectangles
PrintMatrix ();
}
// flag any zero at edge of matrix as 'dead'
static private void EliminateFromEdges(int value)
{
for (int i = 0; i < width; i++)
{
if (matrix [i, 0] == 0)
{
matrix [i, 0] = value;
}
if (matrix [i, height - 1] == 0)
{
matrix [i, height - 1] = value;
}
}
for (int j = 1; j < height - 1; j++)
{
if (matrix [0, j] == 0)
{
matrix [0, j] = value;
}
if (matrix [width - 1, j] == 0)
{
matrix [width - 1, j] = value;
}
}
}
// propagte a value to neighbouring cells
static private void FloodFill (int value)
{
bool change_made = true; // set to true to start things off
while (change_made) {
change_made = false;
for (int i = 1; i < width - 1; i++) {
for (int j = 1; j < height - 1; j++) {
if ((matrix [i, j] == 0) &&
((matrix [i - 1, j] == value) ||
(matrix [i + 1, j] == value) ||
(matrix [i, j - 1] == value) ||
(matrix [i, j + 1] == value))) {
matrix [i, j] = value;
change_made = true;
}
}
}
}
}
static private bool TestIsland (int x, int y)
{
// find convex extend of island
int x2 = x;
int y2 = y;
while (matrix[++x2, y] == 0);
x2--;
while (matrix[x,++y2] == 0);
y2--;
// check inner cells (want all zeroes)
for (int i = x; i <= x2; i++)
{
for (int j = y; j <= y2; j++)
{
if (matrix[i,y] != 0)
{
return false;
}
}
}
// check surrounding cells (want all ones)
x--; y--;
x2++; y2++;
for (int i = x; i <= x2; i++)
{
if ((matrix[i,y] != 1) || (matrix[i,y2] != 1))
{
return false;
}
}
for (int j = y + 1; j <= y2 - 1; j++)
{
if ((matrix[x,j] != 1) || (matrix[x2,j] != 1))
{
return false;
}
}
return true;
}
// for debug purposes
static private void PrintMatrix ()
{
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
switch(matrix[i,j])
{
case DEAD:
Console.Write("-");
break;
case RECT:
Console.Write("+");
break;
default:
Console.Write(matrix[i,j]);
break;
}
}
Console.WriteLine();
}
Console.WriteLine();
}
}
}
此代码的输出
000000001111000
011111101001010
010000101001010
010000101001010
010000101000010
010000101000010
011111101001010
000000001111000
001111000000000
001001001110110
001111001010000
000000001110000
--------1111---
-1111110100101-
-1000010100101-
-1000010100101-
-1000010100001-
-1000010100001-
-1111110100101-
-0000000111100-
-0111100000000-
-0100100111011-
-0111100101000-
--------111----
--------1111---
-111111-1--1-1-
-100001-1--1-1-
-100001-1--1-1-
-100001-1----1-
-100001-1----1-
-111111-1--1-1-
--------1111---
--1111---------
--1001--111-11-
--1111--101----
--------111----
--------1111---
-111111-1--1-1-
-1++++1-1--1-1-
-1++++1-1--1-1-
-1++++1-1----1-
-1++++1-1----1-
-111111-1--1-1-
--------1111---
--1111---------
--1001--111-11-
--1111--101----
--------111----
--------1111---
-111111-1--1-1-
-1++++1-1--1-1-
-1++++1-1--1-1-
-1++++1-1----1-
-1++++1-1----1-
-111111-1--1-1-
--------1111---
--1111---------
--1++1--111-11-
--1111--101----
--------111----
--------1111---
-111111-1--1-1-
-1++++1-1--1-1-
-1++++1-1--1-1-
-1++++1-1----1-
-1++++1-1----1-
-111111-1--1-1-
--------1111---
--1111---------
--1++1--111-11-
--1111--1+1----
--------111----
--------1111---
-111111-1--1-1-
-1++++1-1--1-1-
-1++++1-1--1-1-
-1++++1-1----1-
-1++++1-1----1-
-111111-1--1-1-
--------1111---
--1111---------
--1++1--111-11-
--1111--1+1----
--------111----
答案 4 :(得分:0)
我认为这可能是资源效率低下的问题。不知道那个。
1
s。boolean
&amp;操作下面的行 - &gt;如果它是有效的矩形,它们应该导致100..001
的格式。 (假设您可以执行所有boolean
操作)1
s。