Я ищу какой-то алгоритм "Сортировка Domino", который сортирует список двухсторонних элементов на основе сходства "касательных" сторон последующих элементов.
Предположим, что следующий список, где элементы представлены 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)]
Цель состоит в том, чтобы отсортировать список таким образом, чтобы сумма квадратов разностей касательных концов каждого из двух последующих элементов (потеря) была минимальной:
>>> loss = sum(
... (items[i][1] - items[i+1][0])**2
... for i in range(len(items)-1)
... )
В приведенном выше примере это можно вычислить, просто используя все возможные перестановки, но для списков с большим количеством элементов это становится быстро неосуществимым (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
дает следующий результат с потерей 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)]
Это, однако, не лучшее решение, которое
[(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)]
с потерей 0.0842
. Очевидно, что вышеупомянутый алгоритм хорошо работает для первых нескольких элементов, однако различия для последних растут настолько большими, что они доминируют над потерей.
Есть ли какой-либо алгоритм, который может выполнять такой вид в приемлемой временной зависимости (возможно для списков сотен элементов)?
Если это невозможно сделать именно в виде менее O(n!)
, Есть ли приблизительные подходы, которые, вероятно, вернут хороший результат (небольшая потеря)?