我有一个矩阵,每个单元格中的值(最小值= 1),其中最大值是' max'。
每次,我将每个单元格值修改为其相邻单元格的最高值,即所有8个邻居,并且这同时发生在整个矩阵中。我希望在最小迭代次数之后找到所有单元格的最大值。
这样做的一种强力方法是用零填充矩阵,
for i in range (1,x_max+1):
for j in range(1,y_max+1):
maximum = 0
for k in range(-1,2):
for l in range(-1,2):
if matrix[i+k][j+l]>maximum:
maximum = matrix[i+k][j+l]
matrix[i][j] = maximum
但有没有一种智能且更快捷的方法呢? 提前谢谢。
答案 0 :(得分:4)
我认为这可以通过BFS(广度优先搜索)来解决。
使用' max'与所有矩阵单元同时启动BFS。值。
dis[][] == infinite // min. distance of cell from nearest cell with 'max' value, initially infinite for all
Q // Queue
M[][] // matrix
for all i,j // travers the matrix, enqueue all cells with 'max'
if M[i][j] == 'max'
dis[i][j] = 0 , Q.push( cell(i,j) )
while !Q.empty:
cell Current = Q.front
for all neighbours Cell(p,q) of Current:
if dis[p][q] == infinite
dis[p][q] = dis[Current.row][Current.column] + 1
Q.push( cell(p,q))
Q.pop()
所有i,j的max(dis [i] [j])单元格将为no。需要迭代。
答案 1 :(得分:1)
使用带有" border"。
的数组测试边缘条件是繁琐的,可以通过使数组在边缘周围变大1来避免,每个元素的值为INT_MIN
。
此外,考虑8个测试,而不是双嵌套循环
// Data is in matrix[1...N][1...M], yet is size matrix[N+2][M+2]
for (i=1; i <= N; i++) {
for (j=1; j <= M; j++) {
maximum = matrix[i-1][j-l];
if (matrix[i-1][j+0] > maximum) maximum = matrix[i-1][j+0];
if (matrix[i-1][j+1] > maximum) maximum = matrix[i-1][j+1];
if (matrix[i+0][j-1] > maximum) maximum = matrix[i+0][j-1];
if (matrix[i+0][j+0] > maximum) maximum = matrix[i+0][j+0];
if (matrix[i+0][j+1] > maximum) maximum = matrix[i+0][j+1];
if (matrix[i+1][j-1] > maximum) maximum = matrix[i+1][j-1];
if (matrix[i+1][j+0] > maximum) maximum = matrix[i+1][j+0];
if (matrix[i+1][j+1] > maximum) maximum = matrix[i+1][j+1];
newmatrix[i][j] = maximum
答案 2 :(得分:1)
所有现有答案都需要检查矩阵中的每个单元格。如果您还不知道最大值的位置是什么,这是不可避免的,在这种情况下,Amit Kumar's BFS algorithm具有最佳时间复杂度:O(wh),如果矩阵具有宽度w和高度h。
OTOH,也许你已经知道k个最大值的位置,k相对较小。在这种情况下,以下算法将在O(k ^ 2 *(log(k)+ log(max(w,h))))时间内找到答案,当w或h很大时,这个时间要快得多。它实际上并没有查看任何矩阵条目;相反,它运行二进制搜索以查找候选停止时间(即答案)。对于每个候选停止时间,它构建了那时将被max
占用的矩形集,并检查是否有任何矩阵单元仍被矩形覆盖。
为了解释这个想法,我们首先需要一些术语。将矩形的顶行称为“起始垂直事件”,将其底部边缘下方的行称为“结束垂直事件”。 “基本间隔”是由任何一对垂直事件跨越的行的间隔,它们之间没有任何第三个垂直事件(定义这些间隔的事件对可以来自相同或不同的矩形)。请注意,对于k个矩形,永远不会有超过2k + 1个基本区间 - 这里对h没有依赖性。
基本思路是从左到右穿过与水平事件对应的矩阵列:新的矩形“开始”的列(左边的垂直边缘)矩形),或现有的矩形“完成”(矩形的右垂直边缘右侧的列),跟踪当前覆盖每个基本区间的矩形数量。如果我们检测到由0个矩形覆盖的基本区间,我们可以停止:我们找到了一个包含一个或多个在时间t尚未覆盖的单元格的列。如果我们到达矩阵的右边缘而没有发生这种情况,那么在时间t覆盖所有单元格。
这是一个函数的伪代码,在给定长度为k的数组t
的情况下检查是否有任何矩阵单元未被时间peak
覆盖,其中(peak[i].x, peak[i].y)
是i的位置th max
- 包含原始矩阵中的单元格,按x坐标的递增顺序排列(因此最左边的max
- 包含的单元格位于(peak[1].x, peak[1].y)
)。
Function IsMatrixCovered(t, peak[]) {
# Discover all vertical events and basic intervals
Let vertEvents[] be an empty array of integers.
For i from 1 to k:
top = max(1, peak[i].y - t)
bot = min(h, peak[i].y + t)
Append top to vertEvents[]
Append bot+1 to vertEvents[]
Sort vertEvents in increasing order, and remove duplicates.
x = 1
Let horizEvents[] be an empty array of { col, type, top, bot } structures.
For i from 1 to k:
# Calculate the (clipped) rectangle that peak[i] will cover at time t:
lft = max(1, peak[i].x - t)
rgt = min(w, peak[i].x + t)
top = max(1, peak[i].y - t)
bot = min(h, peak[i].y + t)
# Convert vertical positions to vertical event indices
top = LookupIndexUsingBinarySearch(top, vertEvents[])
bot = LookupIndexUsingBinarySearch(bot+1, vertEvents[])
# Record horizontal events
Append (lft, START, top, bot) to horizEvents[]
Append (rgt+1, STOP, top, bot) to horizEvents[]
Sort horizEvents in increasing order by its first 2 fields, with START considered < STOP.
# Walk through all horizontal events, from left to right.
Let basicIntervals[] be an array of size(vertEvents[]) integers, initially all 0.
nOccupiedBasicIntervalsFirstCol = 0
For i from 1 to size(horizEvents[]):
If horizEvents[i].type = START:
d = 1
Else (if it is STOP):
d = -1
If horizEvents[i].col <= w:
For j from horizEvents[i].top to horizEvents[i].bot:
If horizEvents[i].col = 1 and basicIntervals[j] = 0:
++nOccupiedBasicIntervalsFirstCol # Must be START
basicIntervals[j] += d
If basicIntervals[j] = 0:
return FALSE
If nOccupiedBasicIntervalsFirstCol < size(basicIntervals):
return FALSE # Could have checked earlier, but the code is simpler this way
return TRUE
}
上面的函数可以简单地在t上的二进制搜索中调用,它查找函数返回TRUE的最小t值。
通过使用Fenwick trees,利用任何矩形开始或结束的基本区间集合总是一个区间这一事实,可以消除k / log(k)的另一个因子。