Алгоритм X — это алгоритм для решения задачи точного покрытия . Это простой рекурсивный , недетерминированный , глубинный алгоритм обратного поиска , который Дональд Кнут использовал для демонстрации эффективной реализации под названием DLX, использующей технику танцующих связей . [1] [2]
Точная задача покрытия представлена в алгоритме X матрицей инцидентности A, состоящей из нулей и единиц. Цель состоит в том, чтобы выбрать подмножество строк таким образом, чтобы цифра 1 появлялась в каждом столбце ровно один раз.
Алгоритм X работает следующим образом:
Недетерминированный выбор r означает, что алгоритм рекурсивно выполняет независимые подалгоритмы; каждый подалгоритм наследует текущую матрицу A , но уменьшает ее относительно другой строки r . Если столбец c полностью равен нулю, подалгоритмов нет, и процесс завершается неудачно.
Подалгоритмы образуют дерево поиска естественным образом, с исходной проблемой в корне и с уровнем k, содержащим каждый подалгоритм, который соответствует k выбранным строкам. Обратный поиск — это процесс обхода дерева в прямом порядке, сначала в глубину.
Любое систематическое правило выбора столбца c в этой процедуре найдет все решения, но некоторые правила работают намного лучше других. Чтобы сократить количество итераций, Кнут предлагает, чтобы алгоритм выбора столбца выбирал столбец с наименьшим количеством единиц в нем.
Например, рассмотрим точную задачу покрытия, заданную вселенной U = {1, 2, 3, 4, 5, 6, 7} и набором множеств S = { A , B , C , D , E , F }, где:
Эта задача представлена матрицей:
1 | 2 | 3 | 4 | 5 | 6 | 7 | |
---|---|---|---|---|---|---|---|
А | 1 | 0 | 0 | 1 | 0 | 0 | 1 |
Б | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
С | 0 | 0 | 0 | 1 | 1 | 0 | 1 |
Д | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
Э | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
Ф | 0 | 1 | 0 | 0 | 0 | 0 | 1 |
Алгоритм X с предложенной Кнутом эвристикой выбора столбцов решает эту проблему следующим образом:
Уровень 0
Шаг 1 — Матрица не пуста, поэтому алгоритм продолжается.
Шаг 2 — Наименьшее количество единиц в любом столбце равно двум. Столбец 1 — первый столбец с двумя единицами и поэтому выбирается (детерминированно):
1 | 2 | 3 | 4 | 5 | 6 | 7 | |
---|---|---|---|---|---|---|---|
А | 1 | 0 | 0 | 1 | 0 | 0 | 1 |
Б | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
С | 0 | 0 | 0 | 1 | 1 | 0 | 1 |
Д | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
Э | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
Ф | 0 | 1 | 0 | 0 | 0 | 0 | 1 |
Шаг 3 — В строках A и B в столбце 1 содержится 1, поэтому они выбираются (недетерминированно).
Алгоритм переходит к первой ветви на уровне 1…
1 | 2 | 3 | 4 | 5 | 6 | 7 | |
---|---|---|---|---|---|---|---|
А | 1 | 0 | 0 | 1 | 0 | 0 | 1 |
Б | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
С | 0 | 0 | 0 | 1 | 1 | 0 | 1 |
Д | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
Э | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
Ф | 0 | 1 | 0 | 0 | 0 | 0 | 1 |
1 | 2 | 3 | 4 | 5 | 6 | 7 | |
---|---|---|---|---|---|---|---|
А | 1 | 0 | 0 | 1 | 0 | 0 | 1 |
Б | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
С | 0 | 0 | 0 | 1 | 1 | 0 | 1 |
Д | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
Э | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
Ф | 0 | 1 | 0 | 0 | 0 | 0 | 1 |
2 | 3 | 5 | 6 | |
---|---|---|---|---|
Д | 0 | 1 | 1 | 1 |
2 | 3 | 5 | 6 | |
---|---|---|---|---|
Д | 0 | 1 | 1 | 1 |
1 | 2 | 3 | 4 | 5 | 6 | 7 | |
---|---|---|---|---|---|---|---|
А | 1 | 0 | 0 | 1 | 0 | 0 | 1 |
Б | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
С | 0 | 0 | 0 | 1 | 1 | 0 | 1 |
Д | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
Э | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
Ф | 0 | 1 | 0 | 0 | 0 | 0 | 1 |
1 | 2 | 3 | 4 | 5 | 6 | 7 | |
---|---|---|---|---|---|---|---|
А | 1 | 0 | 0 | 1 | 0 | 0 | 1 |
Б | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
С | 0 | 0 | 0 | 1 | 1 | 0 | 1 |
Д | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
Э | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
Ф | 0 | 1 | 0 | 0 | 0 | 0 | 1 |
2 | 3 | 5 | 6 | 7 | |
---|---|---|---|---|---|
Д | 0 | 1 | 1 | 1 | 0 |
Э | 1 | 1 | 0 | 1 | 1 |
Ф | 1 | 0 | 0 | 0 | 1 |
2 | 3 | 5 | 6 | 7 | |
---|---|---|---|---|---|
Д | 0 | 1 | 1 | 1 | 0 |
Э | 1 | 1 | 0 | 1 | 1 |
Ф | 1 | 0 | 0 | 0 | 1 |
2 | 3 | 5 | 6 | 7 | |
---|---|---|---|---|---|
Д | 0 | 1 | 1 | 1 | 0 |
Э | 1 | 1 | 0 | 1 | 1 |
Ф | 1 | 0 | 0 | 0 | 1 |
2 | 3 | 5 | 6 | 7 | |
---|---|---|---|---|---|
Д | 0 | 1 | 1 | 1 | 0 |
Э | 1 | 1 | 0 | 1 | 1 |
Ф | 1 | 0 | 0 | 0 | 1 |
2 | 7 | |
---|---|---|
Ф | 1 | 1 |
2 | 7 | |
---|---|---|
Ф | 1 | 1 |
2 | 7 | |
---|---|---|
Ф | 1 | 1 |
2 | 7 | |
---|---|---|
Ф | 1 | 1 |
1 | 2 | 3 | 4 | 5 | 6 | 7 | |
---|---|---|---|---|---|---|---|
Б | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
Д | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
Ф | 0 | 1 | 0 | 0 | 0 | 0 | 1 |
На уровне 0 ветвей нет, поэтому алгоритм завершается.
Подводя итог, алгоритм определяет, что существует только одно точное покрытие: S * = { B , D , F }.
Главной целью Кнута при описании алгоритма X было продемонстрировать полезность танцующих связей . Кнут показал, что алгоритм X может быть эффективно реализован на компьютере с использованием танцующих связей в процессе, который Кнут называет «DLX» . DLX использует матричное представление задачи точного покрытия , реализованное в виде двусвязных списков единиц матрицы: каждый элемент 1 имеет ссылку на следующую 1 выше, ниже, слева и справа от себя. (Технически, поскольку списки являются круговыми, это образует тор ). Поскольку задачи точного покрытия, как правило, разрежены, это представление обычно намного эффективнее как по размеру, так и по требуемому времени обработки. Затем DLX использует танцующие связи для быстрого выбора перестановок строк в качестве возможных решений и для эффективного отслеживания (отмены) ошибочных предположений. [1]