Prim的动态位置算法

时间:2013-04-14 06:12:54

标签: c++ algorithm minimum-spanning-tree

假设您有一个输入文件:

<total vertices>
<x-coordinate 1st location><y-coordinate 1st location>
<x-coordinate 2nd location><y-coordinate 2nd location>
<x-coordinate 3rd location><y-coordinate 3rd location>
...

如何使用Prim的算法找到这些位置的MST?我知道这个问题通常使用邻接矩阵来解决。如果适用,任何参考文献都会很棒。

2 个答案:

答案 0 :(得分:0)

如果你已经知道了,很容易。创建邻接矩阵adj [i] [j] =位置i和位置j之间的距离

答案 1 :(得分:0)

我将描述一些Prim的实现,希望能让你到达某个地方。

首先,您的问题并未指定边缘输入程序的方式。您有顶点总数和这些顶点的位置。你怎么知道哪些是连接的?

假设你有边(以及那些边的权重。就像上面所说的@doomster,它可能是点之间的平面距离,因为它们是坐标),我们可以开始考虑我们的实现。维基百科描述了导致三种不同运行时间的三种不同数据结构:http://en.wikipedia.org/wiki/Prim&#39; s_algorithm #Time_complexity

最简单的是邻接矩阵。正如您可能从名称中猜到的那样,矩阵描述的是&#34;相邻&#34;的节点。确切地说,有|v|行和列(其中|v|是顶点数)。 adjacencyMatrix[i][j]的值因使用情况而异。在我们的例子中,它是节点ij之间边缘的权重(即距离)(这意味着你需要以某种方式索引顶点。例如,你可能会将顶点添加到列表中并使用它们在列表中的位置。

现在使用这个邻接矩阵我们的算法如下:

  1. 创建一个包含所有顶点的字典,并按&#34;距离&#34;键入。最初所有节点的距离都是无穷大。
  2. 创建另一个字典以跟踪&#34; parent&#34;。我们用它来生成MST。跟踪边缘更自然,但实际上通过跟踪父母&#34;实际上更容易实现。请注意,如果您根树(即将某个节点指定为根),则每个节点(除根之外)都只有一个父节点。因此,通过制作这个父母的字典,我们将拥有我们的MST!
  3. 使用原始列表中随机选择的节点v创建新列表。
    1. 从距离字典中删除v并将其添加到父字典中,并将其作为父字典(即&#34; root&#34;)。
    2. 浏览该节点的邻接矩阵中的行。对于任何已连接的节点w(对于非连接节点,您必须将其邻接矩阵值设置为某个特殊值.0,-1,int max等)更新其&#34 ;距离&#34;在字典中adjacencyMatrix[v][w]。这个想法是,它不是“无限远”。我们知道我们可以从v到达那里。
  4. 虽然字典不为空(即有节点时我们仍然需要连接)
    1. 查看字典并找到距离最小x
    2. 的顶点
    3. 将其添加到我们新的顶点列表
    4. 对于其每个邻居,请将其距离更新为min(adjacencyMatrix[x][neighbor], distance[neighbor]),并将其父级更新为x。基本上,如果有更快的方式到达neighbor那么应该更新距离字典以反映这一点;如果我们然后将neighbor添加到新列表中,我们知道我们实际添加了哪个边缘(因为父词典表明其父级是x)。
  5. 我们已经完成了。根据需要输出MST(您需要的所有内容都包含在父词典中)
  6. 我承认从维基百科页面到实际实施有一点飞跃,如上所述。我认为解决这个差距的最好方法就是强行执行代码。我的意思是,如果伪代码说&#34;找到min [blah]使得[foo]为真&#34;然后编写你需要执行的任何代码,并将其粘贴在一个单独的方法中。它绝对是低效的,但它是一个有效的实现。图算法的问题在于有30种方法可以实现它们,它们在性能上都有很大不同;维基百科页面只能概念性地描述算法。好处是,一旦你以一些方式实现它,你就可以快速找到优化(&#34;哦,如果我在这个单独的数据结构中跟踪这种状态,我可以进行这种查找方式!快&#34;)。顺便说一句,这个的运行时间是O(|V|^2)。我太懒了,无法详细说明这种分析,但是因为:

    1. 所有初始化都是O(|V|)更糟糕的
    2. 我们执行循环O(|V|)次并花费O(|V|)时间来查看字典以找到最小节点。所以基本上多次找到最小节点的总时间是O(|V|^2)
    3. 更新距离字典所需的时间是O(|E|),因为我们只处理每个边缘一次。由于|E|O(|V|^2),因此O(|V|^2)
    4. 跟踪父母是O(|V|)
    5. 最差的输出树是O(|V| + |E|) = O(|E|)
    6. 添加所有这些(除了(2)之外,所有这些都不应该成倍增加)我们得到O(|V|^2)
    7. 堆的实现是O(|E|log(|V|),它与上面非常相似。唯一的区别是更新距离是O(log|V|)而不是O(1)(因为它是堆),但是找到/删除min元素是O(log|V|)而不是O(|V|) (因为它是一堆)。时间复杂度在分析中非常相似,您最终会得到O(|V|log|V| + |E|log|V|) = O(|E|log|V|)之类的内容。

      实际上......我有点困惑为什么邻接矩阵实现关心它是一个邻接矩阵。它也可以使用邻接列表来实现。我认为关键部分是如何存储距离。在上面概述的实现中,我可能会离开,但我很确定它实现了Prim的算法满足维基百科所概述的时间复杂性约束。