Хотя это более старый вопрос, я попытаюсь ответить на основе аналогичной работы, которую я проделал.
Существует много подходов к решению проблем с ограничениями (в основном это класс сложности NPC).
Это связано с комбинаторной оптимизацией и программированием ограничений. В этом случае ограничения - это геометрия сетки и требование, чтобы слова были уникальными и т. Д.
Подходы рандомизации / отжига также могут работать (хотя и в правильной настройке).
Эффективная простота может быть просто высшей мудростью!
Требования предъявлялись к более или менее полному компилятору кроссвордов и компоновщику (visual WYSIWYG).
Оставляя в стороне конструктор WYSIWYG, схема компилятора была такой:
Загрузить доступные списки слов (отсортированные по длине слова, т.е. 2,3, .., 20)
Найдите слова (то есть слова сетки) на сетке, созданной пользователем (например, слово в точке x, y длиной L, горизонтальной или вертикальной) (сложность O (N))
Вычислить точки пересечения слов сетки (которые необходимо заполнить) (сложность O (N ^ 2))
Вычислить пересечения слов в списках слов с различными буквами алфавита (это позволяет искать подходящие слова с помощью шаблона, например. Тезис Sik Cambon, используемый cwc ) (сложность O (WL * AL))
Шаги .3 и .4 позволяют выполнить эту задачу:
а. Пересечения слов сетки с самим собой позволяют создать «шаблон» для попытки найти совпадения в связанном списке слов доступных слов для этого слова сетки (используя буквы других пересекающихся слов с этим словом, которые уже заполнены на определенном уровне. шаг алгоритма)
б. Пересечение слов в списке слов с алфавитом позволяет найти подходящие (подходящие) слова, которые соответствуют данному «шаблону» (например, «A» на 1-м месте и «B» на 3-м месте и т. Д.)
Таким образом, с этими реализованными структурами данных используемый алгоритм выглядит следующим образом:
ПРИМЕЧАНИЕ: если сетка и база данных слов постоянны, предыдущие шаги можно выполнить один раз.
Первым шагом алгоритма является случайное выделение пустого словосочетания (слова сетки) и заполнение его словом-кандидатом из связанного с ним списка слов (рандомизация позволяет создавать различные солютоны в последовательных выполнениях алгоритма) (сложность O (1) или O (N))
Для каждого еще пустого слота слов (у которого есть пересечения с уже заполненными слотами слов), вычислите отношение ограничений (это может варьироваться, просто число доступных решений на этом шаге) и отсортируйте пустые слоты слов по этому коэффициент (сложность O (NlogN) или O (N))
Переберите пустые слова, вычисленные на предыдущем шаге, и для каждого попробуйте несколько решений cancdidate (убедившись, что «согласованность дуги сохраняется», т. Е. У сетки есть решение после этого шага, если используется это слово ) и отсортировать их в соответствии с максимальной доступностью для следующего шага (т. е. следующий шаг имеет максимально возможные решения, если это слово используется в то время в этом месте и т. д.) (сложность O (N * MaxCandidatesUsed))
Заполните это слово (отметьте его как заполненное и перейдите к шагу 2)
Если не найдено ни одного слова, удовлетворяющего критериям шага .3, попробуйте вернуться к другому подходящему решению некоторого предыдущего шага (здесь критерии могут отличаться) (сложность O (N))
Если найден возврат, используйте альтернативу и при необходимости сбросьте все уже заполненные слова, которые, возможно, потребуется сбросить (пометьте их как незаполненные снова) (сложность O (N))
Если откат не найден, решение не может быть найдено (по крайней мере, с этой конфигурацией, начальным начальным числом и т. Д.)
В противном случае, когда все слова заполнены, у вас есть одно решение
Этот алгоритм выполняет случайное последовательное блуждание дерева решений задачи. Если в какой-то момент есть тупик, он выполняет возврат к предыдущему узлу и следует по другому маршруту. До тех пор, пока не будет найдено решение или не исчерпано количество кандидатов на различные узлы.
Часть согласованности гарантирует, что найденное решение действительно является решением, а случайная часть позволяет создавать разные решения в разных исполнениях, а также в среднем иметь лучшую производительность.
PS. все это (и другие) были реализованы в чистом JavaScript (с параллельной обработкой и WYSIWYG) возможностью
PS2. Алгоритм может быть легко распараллелен для получения более одного (другого) решения одновременно
Надеюсь, это поможет