На прошлой неделе мы работали над созданием самой короткой 1-D строки, используя лучшие 10000 слов в английском языке . Теперь давайте попробуем ту же задачу в 2D!
Что вам нужно сделать, это взять все вышеперечисленные слова и поместить их в прямоугольник как можно меньшего размера, учитывая перекрытия. Например, если бы ваши слова были ["ape","pen","ab","be","pa"]
, то возможный прямоугольник был бы:
.b..
apen
Вышеуказанный прямоугольник даст оценку 5.
Правила:
- Допускается наложение нескольких букв в слове
- Слова могут идти в любом из 8 направлений
- Слова не могут обернуться
- Вы можете использовать любой символ для пустых мест
Вам нужно создать поиск слов, который содержит эти 10000 лучших слов на английском языке (по данным Google). Ваша оценка равна количеству символов в вашем поиске слов (исключая неиспользованные символы). Если есть связь, или если подача доказана, чтобы быть оптимальной, тогда выигрывает заявка, которая сначала отправлена.
источник
Ответы:
Ржавчина,
3143030081 используемые символыЭто своего рода жадный алгоритм: мы начинаем с пустой сетки и многократно добавляем слово, которое можно добавлять с наименьшим количеством новых букв, с разрывом связей, предпочитая более длинные слова. Чтобы сделать это быстро, мы поддерживаем приоритетную очередь размещения слов-кандидатов (реализованную в виде вектора векторов запросов, с вектором для каждого числа новых букв, содержащего раздел для каждой длины слова). Для каждого вновь добавленного письма мы ставим в очередь все места размещения кандидатов, которые проходят через это письмо.
Скомпилируйте и запустите
rustc -O wordsearch.rs; ./wordsearch < google-10000-english.txt
. На моем ноутбуке это работает за 70 секунд, используя 531 МБ ОЗУ.Вывод помещается в прямоугольник с 248 столбцами и 253 строками.
Код
источник
C ++, 27243 символов (248x219, заполнено на 50,2%)
(Публикация этого как нового ответа, потому что я хотел бы сохранить привязку к 1D, которую я изначально опубликовал в качестве ссылки)
Это
нагло срываетв большой степени многом ответом @ AndersKaseorg в его основной структуре, но имеет несколько настроек. Во-первых, я использую свою оригинальную программу для слияния строк, пока наилучшее доступное перекрытие не составит всего 3 символа. Затем я использую метод, описанный AndersKaseorg, для постепенного заполнения 2D-сетки с использованием этих сгенерированных строк. Ограничения тоже немного другие: он все еще пытается добавлять наименьшее количество символов каждый раз, но связи разрываются, отдавая предпочтение сначала квадратным сеткам, затем маленьким сеткам и, наконец, добавляя самое длинное слово.Поведение, которое он отображает, заключается в чередовании периодов заполнения пространства и быстрого расширения сетки (к сожалению, в ней не хватает слов сразу после стадии быстрого расширения, поэтому вокруг краев много пустого пространства). Я подозреваю, что с некоторой настройкой функции стоимости это можно сделать, чтобы получить заполнение пространства лучше, чем 50%.
Здесь есть 2 исполняемых файла (чтобы избежать необходимости повторного запуска всего процесса при итеративном улучшении алгоритма). Вывод одного может быть передан непосредственно в другой:
И наконец, результат:
Альтернативный результат (после исправления нескольких ошибок в программе, которые смещали определенные направления и настраивали функцию стоимости, я получил более компактное, но менее оптимальное решение): 29275 символов, 198x195 (заполнено 75,8%):
Опять же, я мало что сделал для оптимизации этих программ, так что это занимает некоторое время. Но вы можете наблюдать, как он заполняет сетку, что довольно гипнотично.
источник
C ++, 34191 символ «сетка» (при минимальном вмешательстве человека 6 или 7 могут быть легко сохранены)
Это следует рассматривать скорее как границу для 2D-случая, потому что ответ по-прежнему является 1D-строкой. Это просто мой код из предыдущего вызова, но с новой возможностью перевернуть любую строку. Это дает нам гораздо больше возможностей для объединения слов (особенно потому, что в худшем случае непересекающиеся суперструны составляют 26; по одной на каждую букву алфавита).
Для некоторой небольшой визуальной привлекательности в 2D он добавляет разрывы строк в результат, если он может сделать это бесплатно (то есть между словами с перекрытием 0).
Довольно медленно (до сих пор нет кэширования). Вот код:
Результат: http://pastebin.com/UTe2WMcz (на 4081 символ меньше, чем в предыдущем задании)
Совершенно очевидно, что можно добиться некоторой тривиальной экономии, если вертикальные линии
xd
иwv
линии пересекаются с линией монстра. Тогдаhhidetautisbneudui
можно пересекать сd
, иlxwwwowaxocnnaesdda
сw
. Это экономит 4 символа.nbcllilhn
может быть заменено на существующееs
перекрытие (если оно может быть найдено), чтобы сохранить еще 2 (или просто 1, если такого перекрытия не существует, и оно должно быть добавлено по вертикали). Наконец,mjjrajaytq
можно добавить куда-нибудь вертикально для сохранения 1. Это означает, что при минимальном вмешательстве человека можно сохранить 6–7 символов из результата.Я хотел бы получить это в 2D с помощью следующего метода, но я изо всех сил пытаюсь найти способ реализовать его без создания алгоритма O (n ^ 4), который довольно непрактично вычислять!
источник
PHP
этот выполняет работу теоретически; но 10000, вероятно, слишком много слов для рекурсии. Скрипт работает сейчас. (все еще работает 24 часа спустя)
отлично работает на небольших каталогах, но я могу сделать итерационную версию на следующей неделе.
$f=array("pen","op","po","ne","pro","aaa","abcd","dcba"); will output
ABCDalthough this is not an optimal result (scoring was changed ... I´m working on a generator). One optimal result is this:
открытаяЭто также не очень быстро; удаляет только подстроки и сортирует остатки по длине,
остальное - грубой силой: попробуйте вписать слова в прямоугольник, попробуйте на больший прямоугольник, если это не удастся.
Кстати: часть подстроки требует 4,5 минуты на моем компьютере для большого каталога
и сокращает его до 6 190 слов; сортировка по ним занимает 11 секунд.
источник