a_g*_*est 12 python sorting algorithm
我正在寻找某种"多米诺排序"算法,该算法根据后续项目的"切线"边的相似性对双面项目列表进行排序.
假设以下列表中的项目由2元组表示:
>>> items
[(0.72, 0.12),
(0.11, 0.67),
(0.74, 0.65),
(0.32, 0.52),
(0.82, 0.43),
(0.94, 0.64),
(0.39, 0.95),
(0.01, 0.72),
(0.49, 0.41),
(0.27, 0.60)]
Run Code Online (Sandbox Code Playgroud)
目标是对该列表进行排序,使得每两个后续项目(损失)的切线末端的平方差的总和最小:
>>> loss = sum(
... (items[i][1] - items[i+1][0])**2
... for i in range(len(items)-1)
... )
Run Code Online (Sandbox Code Playgroud)
对于上面的示例,这可以通过仅处理所有可能的排列来计算,但是对于具有更多项的列表,这变得很快变得不可行(O(n!)).
如下所示,逐步选择最佳匹配的方法
def compute_loss(items):
return sum((items[i][1] - items[i+1][0])**2 for i in range(len(items)-1))
def domino_sort(items):
best_attempt = items
best_score = compute_loss(best_attempt)
for i in range(len(items)):
copy = [x for x in items]
attempt = [copy.pop(i)]
for j in range(len(copy)):
copy = sorted(copy, key=lambda x: abs(x[0] - attempt[-1][1]))
attempt.append(copy.pop(0))
score = compute_loss(attempt)
if score < best_score:
best_attempt = attempt
best_score = score
return best_attempt, best_score
Run Code Online (Sandbox Code Playgroud)
失去以下结果给出以下结果0.1381:
[(0.01, 0.72),
(0.72, 0.12),
(0.11, 0.67),
(0.74, 0.65),
(0.49, 0.41),
(0.39, 0.95),
(0.94, 0.64),
(0.82, 0.43),
(0.32, 0.52),
(0.27, 0.6)]
Run Code Online (Sandbox Code Playgroud)
然而,这不是最好的解决方案
[(0.01, 0.72),
(0.82, 0.43),
(0.27, 0.6),
(0.49, 0.41),
(0.32, 0.52),
(0.39, 0.95),
(0.94, 0.64),
(0.72, 0.12),
(0.11, 0.67),
(0.74, 0.65)]
Run Code Online (Sandbox Code Playgroud)
失去了0.0842.显然,上述算法对前几个项目表现良好,但是最后一个项目的差异变得如此之大,以至于它们主导了损失.
是否有任何算法可以在可接受的时间依赖性中执行此类排序(对于数百个项目的列表是可行的)?
如果这是不可能做这样的排序正好在不到O(n!)是否有可能返回一个好成绩(小的损失)任何近似的方法?
一般来说,这个问题是寻找一条最小长度的哈密顿路径,与著名的旅行商问题(TSP)密切相关。而且它看起来不像是这个问题的特例,可以在多项式时间内解决。
有大量的启发式算法和近似算法用于求解 TSP。这篇维基百科文章可能是一个很好的起点。