Вы находитесь в одноэтажном подземелье. Есть сокровище, которое защищено запертыми дверями. Двери можно открыть, найдя соответствующие ключи. Ваша цель - найти кратчайший путь к сокровищу.
вход
На входе будет двухмерная сетка, представляющая начальную планировку подземелья.
###########
#$ # g#
# # ####
###G## #
# ####C#
#c @ #
###########
Это вы: @
Это стены: #
Это сокровище: $
Запертые двери - заглавные буквы: A
... Z
Каждая дверь имеет соответствующий ключ в нижнем регистре: a
...z
- Всегда будет один
@
и один$
. - Подземелье всегда будет прямоугольным.
Не гарантируется, что внешний край подземелья является стеной. Это действительное подземелье:
$ A## @ a
- Не гарантируется, что сокровище достижимо. Некоторые подземелья могут быть неразрешимыми.
- Там могут быть двери без ключа, и могут быть ключи, которые не открывают двери.
- Там никогда не будет дубликатов дверей или ключей.
Выход
Ваша программа должна вывести последовательность R
, L
, U
, D
(или 4 других различных символов) , чтобы представить кратчайший возможный путь к сокровищам. Здесь RLUD
означает правый, левый, вверх и вниз соответственно. Если существует несколько кратчайших путей, ваша программа должна распечатать только один из них.
- Вы не можете перейти на стену.
- Вы не можете выйти за пределы подземелья.
- Вы не можете войти в дверь, не подняв ее ключ.
- Переместите на ключ, чтобы забрать его.
- Нет необходимости открывать каждую дверь.
Если невозможно получить сокровище с помощью правильной последовательности ходов, то ваша программа должна завершиться, ничего не печатая. (Завершающий перевод строки разрешен.)
счет
Это код-гольф, поэтому выигрывает ответ с наименьшим количеством байтов.
Тестовые случаи
Каждый тестовый пример будет иметь высоту и ширину подземелья в первой строке и один возможный путь с оптимальным количеством ходов в последней строке.
1 2
@$
R (1)
3 3
$
#Z#
@ z
RRLUUR (6)
3 5
c#d#$
#C#D
@
UUDDRRUUDDRRUU (14)
7 16
c # b # ###@
### #
A ##### ####
d # e
B ## #####
### C ##
# a DE $
RDDDDDDL (8)
16 37
#####################################
# #ijk #a M ##m## # # R #
# # # # # ####
###J#### ############# ### # P b#
#e N h # ####
########## ########### ###### #
# # # $ # # # ####
# D H # # # Q f#
# EcF # #####A##### ###### ####
# G # #####B##### # #
# K #####C##### ############
# # #
########### # #### ##### ####
# # p # # n # #
# d # @ # o# r #
#################Z###################
UUULLLLLLDDLLLDLLLLLLRRRRRRRRRUUURRRRRRRRRRRRRRRDDLLRRUULLUUUUUUURRRRRUURRRDRRRLLLLULLLLLDDLLLLUULLLUDLLLLLULLLRRRRRDRRRRRRDDLLLLLLLLLLLLDDDLLLLLLLDURRRRRRRRDDDDRRRRRRUUUUU (172)
Невозможно достичь сокровища в следующих подземельях. Для этих тестовых случаев не должно быть никакого вывода.
1 3
@#$
7 11
#a#j#$#i#f#
# #E#F#c#H#
# #K#D#A#G#
# #
#C#J# #I#B#
#h#d# #L#g#
#l#e#@#b#k#
10 25
#########################
# fgh # # c B b # #
$ # # # # # #
###### # ##H###E## #
# #
# ######### ##e##
Z @ D y # # #
# ######### F C#
# G # Ad#
#########################
Следующий фрагмент может быть использован для проверки ответов.
function run() {var dungeonText = document.getElementById("dungeon").value;var dungeonLines = dungeonText.split("\n");var height = dungeonLines.length;var width = dungeonLines[0].length;var dungeon = new Array(height);for (i = 0; i < dungeon.length; i++) {var dungeonLine = dungeonLines[i];if (dungeonLine.length != width) {return error("The dungeon is not rectangular");} dungeon[i] = dungeonLines[i].split("");} var movesText = document.getElementById("moves").value;var moves = movesText.trim().split("");var moveCount = moves.length;var rowAt, colAt;for (r = 0; r < dungeon.length; r++) {for (c = 0; c < dungeon[r].length; c++) {if (dungeon[r][c] == '@') {rowAt = r;colAt = c;}}} var treasure = false;while (moves.length > 0) {var move = moves[0];var row = rowAt,col = colAt;switch (move) {case 'R':col++;break;case 'L':col--;break;case 'U':row--;break;case 'D':row++;break;default:return print(dungeon, moves, "Invalid move");} if (row < 0 || col < 0 || row >= height || col >= width) {return print(dungeon, moves, "Out of bounds");} var target = dungeon[row][col];if (target.match(/[A-Z#]/)) {return print(dungeon, moves, "Path blocked");} if (target.match(/[a-z]/)) {var door = target.toUpperCase();for (r = 0; r < dungeon.length; r++) {for (c = 0; c < dungeon[r].length; c++) {if (dungeon[r][c] == door) {dungeon[r][c] = ' ';}}}} if (target == '$') {treasure = true;} dungeon[row][col] = '@';dungeon[rowAt][colAt] = '.';rowAt = row;colAt = col;moves.shift();} if (treasure) {print(dungeon, moves, "Got the treasure in " + moveCount + " moves!");} else {print(dungeon, moves, "Failed to reach treasure");}} function error(message) {var result = document.getElementById("result");result.innerHTML = message;} function print(dungeon, moves, message) {var output = message + "\n";for (r = 0; r < dungeon.length; r++) {for (c = 0; c < dungeon[r].length; c++) {output += dungeon[r][c];} output += "\n";} for (i = 0; i < moves.length; i++) {output += moves[i];} var result = document.getElementById("result");result.innerHTML = output;}
Dungeon:<br/><textarea id="dungeon" name="dungeon" rows="20" cols="40"></textarea><br/>Moves:<br/><textarea id="moves" name="moves" cols="40"></textarea><br/><button id="run" name="run" onclick="run();">Start</button><br/><br/>Result:<br/><textarea id="result" name="result" rows="20" cols="40" disabled></textarea><br/>
источник
Ответы:
Perl
157152151 байтВключает в себя +4 для
-p0
(не может считаться просто продолжением,-e
потому что используется'
в нескольких местах)Запустите с лабиринтом на STDIN:
keymaze.pl
:Заменить
\n
и^H
их буквальными версиями на заявленную оценку. Требуется около 1 часа и чуть менее 2 гигабайт на моей машине, чтобы решить большой лабиринт.источник
Ява 8 -
12821277126812591257 байтЭто проходит все испытания. Однако для некоторых из них это дает несколько отличные результаты (когда существует более одного оптимального способа, что не является проблемой).
Для 4-го теста это дает:
Вместо этого:
Для 5-го теста это дает:
Вместо этого:
Гольф версия:
Неуправляемая версия
Особенности:
Принимая вход
Чтобы запустить его, попробуйте это:
Или , если вы работаете в ungolfed версии, замените
G
«S сTreasureHunt
.Файл должен содержать подземелье. Ввод не должен заканчиваться переводом строки. Кроме того, он принимает только строки в
\n
формате. Это не будет работать с\r\n
или с\r
.Кроме того, он не проверяет и не дезинфицирует ввод. Если входные данные искажены, то поведение не определено (скорее всего, возникнет исключение). Если файл не может быть найден, то будет сгенерировано исключение.
замечания
Моя первая реализация где-то около 1100 байт не смогла решить 5-й тестовый пример за разумное время. Причина этого в том, что моя реализация - это грубая форсирование всех возможных перестановок коллекционных предметов (то есть ключей и сокровищ), которые доступны (то есть не заперты в недоступной комнате).
В худшем случае, со всеми 26 ключами и сокровищами, это будет 27! = 10,888,869,450,418,352,160,768,000,000 различных перестановок.
ФП не уточнил, что ответом должно быть что-то, что принимается в разумные сроки. Однако я считаю, что это лазейка, которую я не хотел бы использовать. Итак, я решил заставить его работать в приемлемое время для всех тестовых случаев. Чтобы добиться этого, моя пересмотренная программа имеет функцию сокращения путей поиска, которая оказалась хуже, чем некоторые уже знают решение. Кроме того, он также кэширует подрешения (т. Е. Динамическое программирование), чтобы избежать пересчета многих идентичных подземелий, которые могут возникнуть. С этим он может решить 5-й тестовый пример всего за одну минуту на моем компьютере.
Решение рекурсивное. Идея заключается в том, чтобы сначала найти искателя приключений (ключ или сокровище). В случае ключа, после того, как искатель достигнет его, создается новое похожее подземелье с удаленными ключом и дверью, и искатель перемещается туда, где находился ключ. При этом сгенерированное простое подземелье решается рекурсивно до тех пор, пока не будет достигнута сокровище или алгоритм не решит, что предмета не существует. Порядок посещаемых предметов является грубым с обрезкой и кэшированием, как объяснено выше.
Поиск пути между искателем приключений и предметами осуществляется с помощью алгоритма, который напоминает и флудфилл, и Дейкстру.
Наконец, я подозреваю, что эта проблема является NP-полной (ну, в общем, ее версия без ограничения количества дверей / ключей). Если это так, не ожидайте решений, которые оптимально решат очень большие подземелья с мириадами дверей и ключей в разумные сроки. Если бы неоптимальные пути были разрешены, то это было бы легко отследить с некоторой эвристикой (просто перейдите к сокровищу, если это возможно, в противном случае перейдите к ближайшему ключу).
источник