【问题标题】:What is the meaning of "from distinct vertex chains" in this nearest neighbor algorithm?在这个最近邻算法中“来自不同的顶点链”是什么意思?
【发布时间】:2011-11-05 05:10:58
【问题描述】:

以下伪代码来自算法设计手册在线预览版的第一章(来自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应该是smtm

首先,我不明白“来自不同的顶点链”是什么意思。其次,i 用作外循环中的计数器,但i 本身从未在任何地方实际使用过!请比我聪明的人解释一下这里到底发生了什么?

【问题讨论】:

  • 有趣,我正要提出同样的问题!
  • 完全相同的问题!一个字一个字地。实际上,我很沮丧,因为我对这本书不够聪明-至少一个人:-P 感谢您的发帖!

标签: algorithm graph-theory pseudocode nearest-neighbor


【解决方案1】:

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

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

【讨论】:

  • 对 1) 的一点澄清:它们仅枚举链的端点。这不是某种 Kruskal 算法,而是 TSP 启发式算法,链仅在端点处增长。
  • 我明白了总体思路,我缺少的是第一次迭代。在第一次迭代中没有端点,那么单个顶点是如何枚举的?例如:-5、-1、0、2。
  • 单例是一个有一个端点的链。一开始每个点都是一个单例。
  • 谢谢,你不知道你的 cmets 有多么有用。我的意思是,这些点是否有特定的处理顺序。这是我的理解:
  • @dhblah 也许我的回答 here 会有所帮助
【解决方案2】:

在解释 Ernest Friedman-Hill(已接受的答案)之后,我是这么看的:

所以来自同一本书的例子(图 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)以获得一个循环。

【讨论】:

  • 我不明白 B-E 会阻止 A-B 和 E-F,因为只选择了不同链中的顶点。这完成了我的理解
  • 一张图讲一千个字,谢谢!但这部分我不明白:“它们之间的 b/c 距离是最小的”。要知道这一点,在我看来,您必须遍历所有其他点才能确定哪些距离是最小的。
  • @stifin A-D 的距离为 1-e,D-E 的距离为 1+e,而且它已经知道了
  • 书的正文里有说明,但是书上没有说明如何知道的。
【解决方案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()

【讨论】:

  • 谢谢你。请问为什么最长的线是弯的而不是直的?曲线使线条变长。
  • @DBedrenko 因为如果你把它画直,那么它会穿过之前画的线。我相信曲线使它看起来更好一些。在倒数第二行中,如果您希望它是直的,请将 draw_arrow 的最后一个参数更改为 0。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-05
  • 1970-01-01
  • 2011-11-08
  • 2017-02-09
  • 2016-03-07
  • 2010-12-30
相关资源
最近更新 更多