这个最近邻算法中“来自不同顶点链”的含义是什么?

时间:2011-08-27 19:14:45

标签: algorithm graph-theory pseudocode nearest-neighbor

以下伪代码来自算法设计手册的在线预览版本的第一章(来自this PDF的第7页)。

这个例子是一个有缺陷的算法,但我仍然真的想要理解它:

  

[...]一个不同的想法可能是重复连接最近的一对   连接不会产生问题的端点,例如   提前终止循环。每个顶点都以它自己的身份开始   单顶点链。将所有内容合并后,我们将结束   一条链包含其中的所有点。连接   最后两个端点为我们提供了一个循环。在执行期间的任何步骤   这个最近对启发式算法,我们将有一组单顶点   和顶点不相交的链可用于合并。在伪代码中:

ClosestPair(P)
    Let n be the number of points in set P.
    For i = 1  to n − 1 do
        d = ∞
        For each pair of endpoints (s, t) from distinct vertex chains
            if dist(s, t) ≤ d then sm = s, tm = t, and d = dist(s, t)
        Connect (sm, tm) by an edge
    Connect the two endpoints by an edge

请注意,smtm应为s m t m

首先,我不明白“来自不同的顶点链”意味着什么。其次,i用作外循环中的计数器,但i本身实际上从未在任何地方使用过!有人比我更聪明,请解释这里真正发生的事情吗?

3 个答案:

答案 0 :(得分:26)

在解释欧内斯特弗里德曼希尔(接受回答)后,我就是这样看的。

所以来自同一本书的例子(图1.4)。 我已经为顶点添加了名称以使其清晰 Figure 1.4

所以在第一步所有顶点都是单顶点链,所以我们连接A-D,B-E和C-F对,它们之间的b / c距离最小。

在第二步,我们有3条链,A-D和B-E之间的距离与B-E和C-F之间的距离相同,所以我们将A-D与B-E连接起来,我们留下了两条链--A-D-E-B和C-F

在第三步,连接它们的唯一方法是通过B和C,b / c B-C比B-F,A-F和A-C短(记住我们只考虑链的端点)。所以我们现在有一条链A-D-E-B-C-F。

在最后一步,我们连接两个端点(A和F)以获得一个循环。

答案 1 :(得分:18)

1)描述说明每个顶点总是属于“单顶点链”(即,它是单独的)或它属于另一个链;顶点只能属于一个链。该算法在每个步骤中说明您选择每个可能的两个顶点对,每个顶点都是它们所属的相应链的端点,并且不属于同一个链。有时候他们会成为单身人士;有时一个或两个已经属于一个非平凡的链,所以你将加入两个链。

2)你重复循环 n 次,这样你最终选择每个顶点;但是,实际的迭代计数不用于任何事情。重要的是你运行循环足够多次。

答案 2 :(得分:3)

虽然问题已经得到解答,但这里是最近对启发式的python实现。它从作为链的每个点开始,然后连续扩展链以构建包含所有点的一个长链。 这个算法确实建立了一条路径,但它不是一个机器人手臂运动的序列,因为这个手臂起始点是未知的。

import matplotlib.pyplot as plot
import math
import random


def draw_arrow(axis, p1, p2, rad):
    """draw an arrow connecting point 1 to point 2"""
    axis.annotate("",
              xy=p2,
              xytext=p1,
              arrowprops=dict(arrowstyle="-", linewidth=0.8, connectionstyle="arc3,rad=" + str(rad)),)


def closest_pair(points):
    distance = lambda c1p, c2p:  math.hypot(c1p[0] - c2p[0], c1p[1] - c2p[1])
    chains = [[points[i]] for i in range(len(points))]
    edges = []
    for i in range(len(points)-1):
        dmin = float("inf")  # infinitely big distance
        # test each chain against each other chain
        for chain1 in chains:
            for chain2 in [item for item in chains if item is not chain1]:
                # test each chain1 endpoint against each of chain2 endpoints
                for c1ind in [0, len(chain1) - 1]:
                    for c2ind in [0, len(chain2) - 1]:
                        dist = distance(chain1[c1ind], chain2[c2ind])
                        if dist < dmin:
                            dmin = dist
                            # remember endpoints as closest pair
                            chain2link1, chain2link2 = chain1, chain2
                            point1, point2 = chain1[c1ind], chain2[c2ind]
        # connect two closest points
        edges.append((point1, point2))
        chains.remove(chain2link1)
        chains.remove(chain2link2)
        if len(chain2link1) > 1:
            chain2link1.remove(point1)
        if len(chain2link2) > 1:
            chain2link2.remove(point2)
        linkedchain = chain2link1
        linkedchain.extend(chain2link2)
        chains.append(linkedchain)
    # connect first endpoint to the last one
    edges.append((chains[0][0], chains[0][len(chains[0])-1]))
    return edges


data = [(0.3, 0.2), (0.3, 0.4), (0.501, 0.4), (0.501, 0.2), (0.702, 0.4), (0.702, 0.2)]
# random.seed()
# data = [(random.uniform(0.01, 0.99), 0.2) for i in range(60)]
edges = closest_pair(data)
# draw path
figure = plot.figure()
axis = figure.add_subplot(111)
plot.scatter([i[0] for i in data], [i[1] for i in data])
nedges = len(edges)
for i in range(nedges - 1):
    draw_arrow(axis, edges[i][0], edges[i][1], 0)
# draw last - curved - edge
draw_arrow(axis, edges[nedges-1][0], edges[nedges-1][1], 0.3)
plot.show()