Предположим, однажды вы копаете большую коробку неиспользуемых компьютерных шнуров и адаптеров (USB-USB mini, VGA-DVI и т. Д.). Повсюду запутанные шнуры создают беспорядок, и вы задаетесь вопросом, не могли бы вы упростить вещи, соединив все шнуры в одну длинную прядь, а затем просто свернув ее.
Вопрос в том, возможно ли соединить все ваши шнуры и адаптеры в одну длинную линию, как это? Очевидно, это не всегда возможно, например, если у вас было только два шнура с совершенно разными разъемами, их нельзя было соединить вместе. Но если бы у вас был третий шнур, который можно подключить к ним обоим, то вы могли бы связать все свои шнуры вместе.
Вам не важно, какие вилки находятся на концах жилы. Им не нужно подключаться друг к другу, чтобы образовать петлю. Вам нужно только знать, возможно ли сделать прядь из шнура, и если да, то как это сделать.
Вызов
Напишите программу или функцию, которая принимает многострочную строку, где каждая строка изображает один из ваших шнуров. Шнур состоит из одной или нескольких черточек ( -
) с вилкой на каждом конце. Штекер всегда является одним из 8 символов ()[]{}<>
.
Итак, вот некоторые допустимые шнуры:
>->
(--[
}-{
<-----]
(---)
Но это не так:
-->
(--
)--
[{
---
При подключении шнуров только штекеры с одинаковым типом кронштейна могут быть соединены вместе.
Итак, вот некоторые действительные кабельные соединения:
...---((---...
...---))---...
...---]]---...
...---{{---...
...---<<---...
И это недействительно:
...---()---...
...---)(---...
...---{]---...
...---{[---...
...---><---...
...--->)---...
Если все шнуры на входе можно переставить и соединить вместе в одну длинную цепь, то выведите эту цепь в стандартный вывод на одной строке (с дополнительным завершающим символом новой строки). При наличии нескольких решений вы можете выбрать любое из них для вывода. Если создание одной цепи невозможно, ничего не выводится (или выводится пустая строка с необязательным завершающим символом новой строки).
Например, если вход
[-->
{---]
>----{
выход может быть
[-->>----{{---]
где все шнуры связаны вместе.
Однако, если вход был
[-->
{---]
Шнуры не могут быть подключены, поэтому не будет никакого выхода.
Обратите внимание, что шнуры могут быть перевернуты столько, сколько необходимо для создания соединений. например, [-->
и <--]
фактически являются одним и тем же шнуром, потому что они могут выполнять соединения одного типа. Некоторые выходы могут зависеть от переворачивания входных шнуров.
Например
(-[
}--]
может иметь выход
(-[[--{
где перевернут второй шнур, или
}--]]-)
где первый шнур перевернут.
(Обратите внимание, что в целом перелистывание всего выхода допустимо, потому что это то же самое, что изначально переворачивание каждого шнура в отдельности.)
Длина шнуров в выходных данных должна, конечно, соответствовать длинам соответствующих входных шнуров. Но шнуры могут быть переупорядочены и перевернуты столько, сколько вы хотите, чтобы сделать весь шнур. На входе всегда будет хотя бы один шнур.
Самый короткий код в байтах побеждает.
Тестовые случаи
Случаи с выходом:
[-->
{---]
>----{
gives
[-->>----{{---]
or
[---}}----<<--]
(-[
}--]
gives
(-[[--{
or
}--]]-)
(-)
gives
(-)
[--{
gives
[--{
or
}--]
[-]
]-[
gives
[-]]-[
or
]-[[-]
[----->
)------------[
{--<
}---)
could give
[----->>--}}---))------------[
or
>--}}---))------------[[----->
or
}---))------------[[----->>--}
or
{--<<-----]]------------((---{
etc.
>-->
>->
>--->
could give
>-->>->>--->
or
>--->>-->>->
or
>->>-->>--->
or
<--<<---<<-<
etc.
(-]
]->
>-}
}-)
)-[
[-<
<-{
{-(
could give
(-]]->>-}}-))-[[-<<-{{-(
or
{-((-]]->>-}}-))-[[-<<-{
or
<-{{-((-]]->>-}}-))-[[->
etc.
Случаи без выхода:
[-->
{---]
[-]
[-]
(-]
]->
}-)
>->
>-->
]---]
[-------------------]
]-------------------[
[-----------------]
[-----------------]
{--[
]--}
Ответы:
Не читается , 3924 байта
Это первый раз, когда я реализовал что-то вроде структуры стека вызовов в Unreadable.
(Первая версия этого была более 5300 байтов, просто чтобы дать представление о том, как много я играл в гольф.)
объяснение
Рассмотрим этот пример ввода:
На протяжении большей части исполнения лента выкладывается следующим образом:
Ячейки с 0 по 5 являются местоположениями для различных переменных.
Ячейка 6 и далее содержит всю информацию о наборе кабелей в вашей коробке:
Оставшиеся ячейки после «нулевого терминатора» содержат стек. Каждый «стековый фрейм» представляет собой отдельную ячейку, которая указывает на первую ячейку кабеля (ячейка «начальная вилка»). В приведенном выше примере, когда программа решит, что она нашла решение, стек будет содержать 6 (ссылаясь
>--{
на первый кабель) и 21 (ссылаясь{---]
на зеркало второго кабеля).Программа проходит в три основных этапа:
Первый этап (чтение входных данных и создание структуры кабелей) использует только ячейки № 1 (которые я назову
p
) и № 2 (которые я назовуch
) и работает в цикле while следующим образом:В то время как условие: увеличьте
p
на 6, прочитайте следующий символ (стартовый плагин) в ячейку*p
и убедитесь, что это не так-1
(EOF).Читайте последующие символы
*(p+2)
и считайте их*(p+1)
до тех пор, пока мы не встретим что-либо, кроме-
(дефис). В этот момент*(p+1)
будет содержаться количество дефисов (длина кабеля) и*(p+2)
последний не дефисный символ (концевая заглушка). (Мы также копируем дефисные символы в ячейку # 5, чтобы мы могли получить доступ к этому ASCII-коду позже на этапе вывода.)В цикле while найдите зеркальный штекер и сохраните его в точке
*(p+3)
, затем увеличивайтеp
на 2, пока*p
не достигнете нуля. Цикл выглядит так в псевдокоде:Этот цикл всегда будет выполнять две итерации (начальный и конечный разъем) и сохранять результаты в четвертой и шестой ячейке этого кабеля. Теперь, если вы обратили внимание, вы поймете, что шестая ячейка действительно является правильным местом для зеркальной концевой заглушки, но зеркальная стартовая заглушка находится в ячейке с надписью «логическое значение, указывающее оригинальный кабель». Это нормально, потому что нам нужно, чтобы эта ячейка была ненулевым значением.
Поскольку
p
только что было увеличено всего 4, теперь он указывает на ячейку, помеченную как «логическое значение, указывающее, что кабель используется». Установите*(p+3)
значение*(p-1)
. Это ставит зеркальный стартовый разъем в нужное место.Прочитайте (и отбросьте) еще один символ (который, как мы ожидаем, будет новой строкой, но программа не проверяет это).
p
изначально начинается с 0, но увеличивается на 6 внутри условия while, поэтому данные кабеля начинаются с ячейки # 6.p
увеличивается на 4 внутри тела петли, и, таким образом, всего 10 для каждого кабеля, что именно то, что нам нужно.На втором этапе, клетки # 0-4 заняты переменные , которые я буду называть
a
,p
,q
,m
, иnotdone
. (Ячейка № 5 все еще помнит ASCII-код дефиса.)Чтобы подготовиться к этапу 2, нам нужно установить
*p
значение 0 (ячейка, помеченная как «нулевой терминатор»), чтобы она могла действовать как терминатор для списка кабелей; мы также устанавливаемq
(который является указателем нашего стека) наp+1
(то есть ячейку после «нулевого терминатора»; именно здесь начинается стек);*q
1 (первый элемент в стеке; почему 1 станет очевидным позже); иnotdone
до 1. Все это делается в одном утверждении:Второй этап - это также цикл while. Его состояние просто
notdone
. На каждой итерации этого цикла while может произойти любая из следующих четырех вещей:*q
к другому подходящему кабелю (который мы быстро помечаем как «используемый» вместе с его близнецом), а затем выполнить рекурсию (т.е. создать новый стековый кадр).*q
потому что больше не существует подходящего кабеля, поэтому нам нужно вернуться назад (удалите стековый фрейм и пометьте предыдущий кабель и его двойник как «больше не используемые»).*q
потому что больше нет подходящего кабеля, и мы не можем вернуться, потому что мы достигли дна стека. Это означает, что нет решения.Тело цикла проверяет каждое из этих четырех условий в указанном порядке. Вот подробности:
Установите
m
иp
равным 1, а в цикле while увеличивайтеp
на 5 (таким образом итерируя по кабелям) и проверяйте, установлено ли*(p+4)
(«используется»). Если это не так, установитеm
значение 0. В конце этого циклаm
сообщите нам, все ли кабели используются. Если это так, установитеnotdone
0, чтобы завершить основной цикл. В противном случае перейдите к шагу 2 ниже.Установите
p
значение*q
(кабель в верхней части стека) и в цикле while, аналогичном описанному выше, увеличьтеp
на 5 для итерации по кабелям. Начиная с того, что*q
мы рассматриваем только те, которые мы еще не рассматривали; однако помните, что начальное значение для нового стекового кадра равно 1, поэтому первый рассматриваемый кабель - это тот, который находится в ячейке 6, который действительно является первым кабелем.Для каждого кабеля нам нужно
*(p+4)
убедиться, что он еще не используется, а также, что либо он*(q-1)
равен нулю (это означает, что мы находимся в нижней части стека, поэтому нет никаких ограничений на пусковую вилку), либо*p
(начало кабеля plug) равно*(*(q-1)+2)
(концевой разъем кабеля чуть ниже стека). Мы проверяем равенство, установивa
в*(*(q-1)+2)
иm
к*p+1
а затем декремента как в то время как цикл. Это+1
потому, чтоm
уменьшается внутри условия while, поэтому он уменьшается еще раз больше, чемa
. Еслиa
в конце это ноль, два штекера равны.Таким образом, если либо
*(q-1)
был равен нулю, либо сравнение на равенство выполнено успешно, кабель подходит. Установите,*q
чтобыp
заменить кабель в верхней части стека новым; установитеm
на то же самое, чтобы указать, что мы нашли соответствующий кабель; а затем уменьшитьp
. Этот декремент - небольшая хитрость, заставляющая цикл while (итерацию по кабелям) завершаться рано; он снова увеличитсяp
на 5, перенеся его в ячейку, содержащую флаг «используется» этого кабеля, и мы знаем, что это ноль, потому что мы только что проверили это. Наконец, после итерации по кабелю цикла while мы проверяем, неm
является ли он ненулевым. Если это так, мы нашли соответствующий кабель иp
указываем на флаг «в использовании» для этого соответствующего кабеля. Установите 1, чтобы пометить его как используемый. Также установлено*(*(p-1) ? p+5 : p-5)
1, чтобы отметить его близнец, как в использовании. Наконец, увеличьтеq
и установите новый*q
в 1, чтобы создать новый стек стека.Если после итерации по кабелю цикла while мы обнаружим,
m
что он равен нулю, подходящих кабелей больше нет, поэтому нам нужно вернуться назад. Уменьшите значениеq
для перемещения вниз по стеку и проверьте, что он все еще указывает на кабель (ненулевое значение). Если это так, пометьте этот кабель и его двойник как неиспользуемые. (Мы сохраняем значение*q
in,p
чтобы сделать это выражение короче в коде.)Если после уменьшения
q
мы обнаруживаем, что он указывает на нулевое значение, то это «нулевой терминатор», что означает, что мы опустошаем стек. Мы заключаем, что нет решения. Мы устанавливаемnotdone
0, чтобы завершить основной цикл.Третий этап - выходной. Есть две вещи, которые могут произойти:
Удобно, если бы не было не решение,
p
равно нулю , потому что мы устанавливаем его к значению*q
перед проверкой , что на ноль; и если было решение,p
оно указывает на «нулевой терминатор», потому что он просто перебирает кабели, поэтому теперь мы можем использовать егоp
для перебора стека. Так что просто итерируйте по стеку, выводя для каждого кабеля начальный плагин (*(*p)
), дефисы (уменьшая*(*p+1)
в цикле while; используя код ASCII дефиса, хранящийся в ячейке # 5) и концевой плагин (*(*p+2)
). Не берите в голову, что это разрушает информацию о длине кабеля; нам это больше не нужно.источник
CJam, 67
Попробуйте онлайн
Примечание: ссылка использует последний код из хранилища (отправлено, но еще не выпущено), так как содержит исправление ошибки.
Объяснение:
Программа просто пробует все перестановки и все ориентации шнуров.
источник
(-] ]-> >-} }-) )-[ [-< <-{ {-(
.JavaScript (ES6), 206
Рекурсивная функция
Более читаемый
Тест
источник
Javascript, 800 байт
Это далеко не оптимизированное решение, но вот быстрый взлом вместе в javascript (никакой необычной ecma5 или чего-то еще, потому что я этого не знаю).
Недооценено, вот оно ... Я уверен, что по крайней мере 2 для циклов здесь не нужны, и что проверка на вход одного элемента в верхней части и совпадение одного элемента в нижней части является вонючей ... но, похоже, работает и обрабатывает входные данные теста.
источник
s.charAt(x)
===s[x]
Python 3, 217 байт
( Демонстрация на Ideone )
источник
(-] ]-> >-} }-) )-[ [-< <-{ {-(
?Луа, 477 байт
Принимает шнуры в качестве аргументов командной строки
источник
Python 3.5,
448432427424286311 байт:( +25, так как была ошибка, когда вывод может быть длиннее, чем должен быть для некоторых входов )
Работает отлично!
за исключением входов с 7 или более значениями. Это занимает много времени, скорее всего, потому что он должен пройти через все эти перестановки ввода плюс обратный ввод . Я постараюсь это исправить, если и когда смогу, но сейчас это кажется достаточно хорошим.Теперь все хорошо! Если только я мог каким-то образом использовать этотtry-except
блок в понимании списка, он мог бы быть немного короче и выглядеть намного лучше. Тем не менее, в настоящее время работает для всех тестовых случаев, и, лучше всего, он не использует ни одного импорта! :)Попробуйте онлайн! (Ideone) (284 байта здесь)
(Совет: чтобы попробовать это, просто выберите «fork», а затем введите ваши варианты, разделенные пробелами , и выберите «run»)
объяснение
В основном, что происходит ...
B
создается из входных данных, разбивая его на пустом месте на составляющие его «шнуры».M
это созданная мной строка, которая при оценке возвращает список, вB
котором содержатся все шнуры, но на этот раз обратном направлении .M
в конечном итоге объединяется сB
самим собой для создания спискаf
со всеми возможными ориентациями «шнуров».d
который будет инициализирован первым значением (значением).f[0]
) изf
.d
итерируются, и последний символ каждого значения сравнивается с первым символом каждого элемента вf
, и когда совпадение найдено, этот символ выталкивается (или удаляется) и возвращается из спискаf
. Это происходит до тех пор, пока значение a неIndexError
будет увеличено или длина списка неd
превысит,B
а значение a неNameError
будет поднято после вызоваE
, оба из которых обрабатываются, а затемd
содержимое списка объединяется в строку и возвращается до тех пор, пока длина спискаd
больше чем или равно длине спискаB
. В противном случае возвращается пустая строка (''
), посколькуd
длина не совпадает со значением,B
означающим, что все «шнуры» в спискеB
не может быть объединен в один длинный "шнур".источник
<!-- language: lang-python -->
Что это меняет?