【问题标题】:Shortest Distances To One Of Multiple Potential Destinations到多个潜在目的地之一的最短距离
【发布时间】:2016-07-03 08:12:45
【问题描述】:

在一次编程测试中,我被要求解决一个问题,即我必须找到从矩形图上的每个节点到图上一组可能目的地之一的最短距离。我能够创建一个通过所有测试的解决方案,但我相当肯定那里有更有效的算法。

C11--C12--C13--C14
 |    |    |    |
FGB--C22--C23--C24
 |    |    |    |
C31--C32--C33--C34
 |    |    |    |
C41--FGB--C43--C44
 |    |    |    |
C51--C52--C53--C54
 |    |    |    |
C61--C62--C63--FGB

例如,在上图中,假设每个“FGB”代表五个人(因为它很好吃)。每个“Cxx”代表一个客户。它本质上是,“每个客户离最近的五个人有多远?”所以 C11 距离为 1,C12 距离为 2,依此类推。所有边的权重=1。

Floyd-Warshall 是我要找的吗?我并不真正关心所有配对。

您有什么想法或参考资料可以指点我吗?非常感谢。

【问题讨论】:

  • 我是不是遗漏了什么,或者你能不能只计算每个点坐标的距离,即(x, y)到(x', y')的距离是abs (x - x') + abs (y - y')?
  • 从 FGB 开始做 BFS。
  • 是的 @gnasher729 所以对于每个 Cxx 你会为每个 FGB 重复,对吧?那不是 O(m*n) 吗?
  • 图是不是一直都是这样的矩阵布局,每个内部节点有4个邻居,分别是正北、东、南、西的节点?或者这只是一个例子,图表是否可以有任意数量的邻居,与显示格式中的位置无关?
  • 图形总是有这种矩形布局,但它可以是任意大小,并且可以有任意数量的 FGB。任何不是 FGB 的节点都是客户。您知道 FGB 的起始坐标(您不必搜索它们)。

标签: algorithm


【解决方案1】:

有一个简单的解决方案,可以分两次使用。

第一次传球是向前的,一行一行的。对于每个节点,您都会逐步评估到上方左侧最近目标的距离。

D(node)= if target node => 0 else min(D(left neighbor) + 1, D(top neighbor) + 1)

第二遍是向后的。最终距离评估为

D(node)= min(D(node), D(right neighbor) + 1, D(bottom neighbor) + 1)

在记录新值的同时,可以记录对应目标的位置。

(当邻居不存在时,按照惯例,距离是无限的。)

【讨论】:

  • 谢谢@yves-daoust。我试图在这里发表评论,但我的回复太长了,所以我做了一个新的答案来回复你。 stackoverflow.com/a/38172165/5971378 与我想出的相比,这似乎很简单。真希望我有一台时光机。生活就是学习。
  • @CashStramel:这是数字图像处理中的一个已知问题。它计算“到二值图像的拓扑距离”。有趣的是,还可以计算与像素数成正比的欧几里得距离;不过,这更复杂。请参阅“采样函数的距离变换,P. Felzenszwalb,D. Huttenlocher,计算理论,第 8 卷,第 19 期,2012 年 9 月”
【解决方案2】:

对于任意图大小、任意数量的目标节点 (FGB),以下 BFS 算法将是最有效的:

nodes = set of all nodes
currentNodes = set of target nodes (FGB)

for each node in nodes:
    dist[node] = infinity

for each node in currentNodes:
    dist[node] = 0

while currentNodes is not empty:
    newNodes := []
    for each node in currentNodes:
        for each neighbor of node:
            if dist[neighbor] > dist[node] + 1 then:
                dist[neighbor] := dist[node] + 1
                newNodes.add(neighbor)
    currentNodes := newNodes 

for each node 循环将总共访问每个节点一次。

for each neighbor 循环将在每个节点最多迭代 4 次,假设图形是矩形的。

这意味着内部 if 条件将被执行接近 4n 次,即这是 O(n)。根据使用的数据结构,数量可以是 4n-4√n,因为边界节点的邻居较少,但这仍然是 O(n)

请注意,如果您的目标节点 (FGB) 少于 4 个,则使用图形的矩形属性计算距离会更快(尽管在大 O 术语中并不重要)。您可以使用这个公式来做到这一点,其中 m 是目标节点 (FGB) 的数量:

dist[node at [i,j]] := min( abs(i-FGB[0].column)+abs(j-FGB[0].row),
                            abs(i-FGB[1].column)+abs(j-FGB[1].row),
                            ... 
                            abs(i-FGB[m-1].column)+abs(j-FGB[m-1].row)
                          )

这具有O(n.m)的时间复杂度,对于限制为某个常数的m仍然是O(n)并且可能比更通用的解决方案更快。

算法可以利用这一点,根据 m 的值,可以选择应用哪种方法。

【讨论】:

  • 你不需要检查if dist[neighbor]...,因为所有的权重都是1
  • @anatolyg。在该算法中,dist[neighor] 不是节点到其邻居的距离,而是邻居到最近的目标单元的距离,在开始时设置为无穷大或零。该测试实际上等同于dist[neighbor] == infinity,但从数学角度来看有点奇怪,所以我只是做了大于检查。
【解决方案3】:

作为对@yves-daoust 的回应(我知道我不应该用全新的答案来回应其他答案,但这对于“回应答案”对话框来说太长了)。

所以整个事情看起来像这样?

// O(n)
for each node:
  set node distance to infinity

// O(m)
for each FGB in FGB coordinate list
  directly set corresponding node distance to infinity

// O(n)  
for each i in row
  for each j in column
    if left and up exist
      set node(i,j) to min(node(i,j), left+1, up+1)
    else if left exists
      set node(i,j) to min(node(i,j), left+1)
    else if up exists
      set node(i,j) to min(node(i,j), up+1)

// O(n)
for each i in row (reverse)
  for each j in column (reverse)
    if right and down exist
      set node(i,j) to min(node(i,j), right+1, down+1)
    else if right exists
      set node(i,j) to min(node(i,j), right+1)
    else if down exists
      set node(i,j) to min(node(i,j), down+1)

整个过程是 O(3n+m) = O(n+m)。对吗?

【讨论】:

  • 复杂度是 O(n.m),而不是 O(n+m),因为存在嵌套循环。这是不可避免的,因为必须至少阅读所有元素一次。
  • 我可以看到 (i, j) 上的嵌套循环在本地被视为 O(i.j),但这只是允许我一次评估每个节点 n 的机制。所以从更高的层次来说,不是每遍都是O(n)?
  • 哎呀,对不起,我误解了 m 和 n 的含义。由于m
猜你喜欢
  • 2016-05-08
  • 1970-01-01
  • 1970-01-01
  • 2018-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多