我试图解决距离变换问题(使用曼哈顿的距离)。基本上,给出0和1和1的矩阵,程序必须将每个位置的距离分配给最接近的1。例如,对于这个
0000
0100
0000
0000
距离变换矩阵
2123
1012
2123
3234
我脑子里的可能解决方案是:
最慢的(最慢的,因为我试图实现它们 - 它们在很大的矩阵上滞后):
蛮力 - 对于该程序读取的每1个,从开始到结束相应地改变距离。
广度优先搜索0' s - 每0,程序查找最近的1个内部。
与2相同,但从1开始标记内外的每个距离。
快得多(从其他人的代码中读取)
广度优先搜索1&#39>
1. Assign all values in the distance matrix to -1 or very big value.
2. While reading matrix, put all positions of 1's into queue.
3. While queue is not empty
a. Dequeue position - let it be x
b. For each position around x (that has distance 1 from it)
if position is valid (does not exceed matrix dimensions) then
if distance is not initialized or is greater than (distance of x) + 1 then
I. distance = (distance of x) + 1
II. enqueue position into queue
我想问一下这个问题是否有更快的解决方案。我试图搜索距离变换的算法,但大多数都处理欧几里德距离。
提前致谢。
答案 0 :(得分:5)
广度优先搜索将执行Θ(n*m)
次操作,其中n
和m
是矩阵的宽度和高度。
您需要输出Θ(n*m)
个数字,因此从理论的角度来看,您的速度不会快于此。
我假设您对涉及缓存和此类优化的讨论不感兴趣。
请注意,此解决方案适用于更有趣的情况。例如,想象同样的问题,但可能有不同的“来源”:
00000
01000
00000
00000
00010
使用BFS,您将获得具有相同时间复杂度的以下距离 - 最近源:
21234
10123
21223
32212
32101
但是,对于单一来源,还有另一种解决方案可能在实践中具有稍好的性能(即使复杂性仍然相同)。
之前,让我们观察以下属性。
属性:如果source位于(a,b),则点(x,y)具有以下曼哈顿距离:
d(x, y) = abs(x - a) + abs(y - b)
这应该很容易证明。所以另一种算法是:
for r in rows
for c in cols
d(r, c) = abc(r - a) + abs(c - b)
非常简短。
除非您编写并测试它,否则没有简单的方法来比较这两种算法。假设有效的有界队列实现(带有数组),每个单元有以下主要操作:
if
s 这实际上取决于编译器及其优化以及特定的CPU和内存架构,以确定哪些性能会更好。
那就是说,我建议你选择一个看似简单的东西。但请注意,对于多个源,在第二个解决方案中,您需要在阵列上进行多次传递(或在一次传递中进行多次距离计算),对于足够多的源,这肯定会比BFS的性能更差。
答案 1 :(得分:2)
你根本不需要队列或类似的东西。请注意,如果(i,j)距离(k,l)的距离为d,则实现该距离的一种方法是向左或向右| i-k |时间然后上升或下降| j-l |次。
因此,使用大数字初始化矩阵,并在输入中有1
的任何地方粘贴零。现在做这样的事情:
for (i = 0; i < sx-1; i++) {
for (j = 0; j < sy-1; j++) {
dist[i+1][j] = min(dist[i+1][j], dist[i][j]+1);
dist[i][j+1] = min(dist[i][j+1], dist[i][j]+1);
}
dist[i][sy-1] = min(dist[i][sy-1], dist[i][sy-2]+1);
}
for (j = 0; j < sy-1; j++) {
dist[sx-1][j] = min(dist[sx-1][j], dist[sx-2][j]+1);
}
此时,您已找到所有仅涉及向下或向右的最短路径。如果你做同样的事情上升和离开,dist[i][j]
将给你从输入矩阵中的(i,j)到最近的1
的距离。