以下伪代码来自算法设计手册的在线预览版本的第一章(来自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
请注意,sm
和tm
应为s
m
和t
m
子>
首先,我不明白“来自不同的顶点链”意味着什么。其次,i
用作外循环中的计数器,但i
本身实际上从未在任何地方使用过!有人比我更聪明,请解释这里真正发生的事情吗?
答案 0 :(得分:26)
在解释欧内斯特弗里德曼希尔(接受回答)后,我就是这样看的。
所以来自同一本书的例子(图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()