Załóżmy, że pewnego dnia przekopujesz się przez duże pudło nieużywanych kabli komputerowych i adapterów (USB na USB mini, VGA na DVI itp.). Wszędzie są splątane sznury, które robią niezły bałagan, i zastanawiasz się, czy możesz uprościć rzeczy, łącząc wszystkie sznury w jedną długą nić, a następnie po prostu zwijając.
Pytanie brzmi, czy możliwe jest połączenie wszystkich przewodów i adapterów w jedną długą linię taką jak ta? Oczywiście nie zawsze jest to możliwe, np. Jeśli masz tylko dwa przewody z całkowicie różnymi wtyczkami, nie można ich ze sobą połączyć. Ale jeśli masz trzeci przewód, który można podłączyć do obu z nich, możesz połączyć wszystkie przewody razem.
Nie obchodzi Cię, jakiego rodzaju wtyczki znajdują się na końcach nici typu all-cord. Nie muszą się ze sobą łączyć, aby utworzyć pętlę. Chcesz tylko wiedzieć, czy możliwe jest wykonanie nici z przewodem, a jeśli tak, to jak to zrobić.
Wyzwanie
Napisz program lub funkcję, która pobiera ciąg wielowierszowy, w którym każda linia przedstawia jeden z posiadanych przewodów. Przewód składa się z jednego lub więcej myślników ( -
), z wtyczką po obu stronach. Wtyczka jest zawsze jednym z 8 znaków ()[]{}<>
.
Oto niektóre prawidłowe przewody:
>->
(--[
}-{
<-----]
(---)
Ale to nie są:
-->
(--
)--
[{
---
Podczas podłączania przewodów można łączyć ze sobą tylko wtyczki dokładnie tego samego typu wspornika.
Oto niektóre prawidłowe połączenia kablowe:
...---((---...
...---))---...
...---]]---...
...---{{---...
...---<<---...
A te są nieprawidłowe:
...---()---...
...---)(---...
...---{]---...
...---{[---...
...---><---...
...--->)---...
Jeśli wszystkie sznury na wejściu mogą zostać uporządkowane i połączone razem w jedną długą nić, wyprowadzić tę nić na stdout w jednym wierszu (z opcjonalnym końcowym znakiem nowej linii). Gdy istnieje wiele rozwiązań, możesz wybrać jedno z nich do wydrukowania. Jeśli utworzenie pojedynczej nici nie jest możliwe, nic nie wypisz (lub wypisz pusty ciąg z opcjonalnym końcowym znakiem nowej linii).
Na przykład, jeśli dane wejściowe to
[-->
{---]
>----{
wyjście może być
[-->>----{{---]
gdzie wszystkie sznury są ze sobą połączone.
Jednak jeśli dane wejściowe były
[-->
{---]
przewody nie mogą być podłączone, więc nie będzie wyjścia.
Należy pamiętać, że sznury można odwrócić tak bardzo, jak to konieczne do wykonania połączeń. np. [-->
i <--]
są faktycznie tym samym przewodem, ponieważ mogą wykonywać ten sam typ połączeń. Niektóre wyjścia mogą zależeć od odwrócenia przewodów wejściowych.
Na przykład
(-[
}--]
może mieć wynik
(-[[--{
gdzie drugi przewód jest odwrócony, lub
}--]]-)
gdzie pierwszy przewód jest odwrócony.
(Zauważ, że ogólnie przerzucanie całego wyjścia jest poprawne, ponieważ jest takie samo, jak początkowo przerzucanie każdego przewodu osobno).
Długości przewodów wyjściowych powinny oczywiście odpowiadać długości odpowiednich przewodów wejściowych. Ale sznury mogą być ponownie uporządkowane i odwrócone tak, jak chcesz, aby uzyskać pasmo wszystkich kabli. Wejście zawsze będzie zawierało co najmniej jeden przewód.
Najkrótszy kod w bajtach wygrywa.
Przypadki testowe
Obudowy z wyjściem:
[-->
{---]
>----{
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.
Obudowy bez wyjścia:
[-->
{---]
[-]
[-]
(-]
]->
}-)
>->
>-->
]---]
[-------------------]
]-------------------[
[-----------------]
[-----------------]
{--[
]--}
Odpowiedzi:
Nieczytelny , 3924 bajtów
Po raz pierwszy zaimplementowałem w Unreadable strukturę przypominającą stos wywołań.
(Pierwsza wersja tego miała ponad 5300 bajtów, żeby dać wyobrażenie o tym, ile grałem w golfa.)
Wyjaśnienie
Rozważ przykładowe dane wejściowe:
Przez większość wykonywania taśma jest układana w następujący sposób:
Komórki od 0 do 5 to lokalizacje różnych zmiennych.
Komórka 6 i następne zawierają wszystkie informacje o zestawie kabli w twoim pudełku:
Pozostałe komórki po „zerowym terminatorze” zawierają stos. Każda „ramka stosu” jest pojedynczą komórką, która wskazuje na pierwszą komórkę kabla (komórkę „start plug”). W powyższym przykładzie, gdy program zdecyduje, że znalazł rozwiązanie, stos będzie zawierał 6 (odnosząc się do
>--{
pierwszego kabla) i 21 (odnosząc się do{---]
lustra drugiego kabla).Program przebiega w trzech głównych etapach:
Pierwszy etap (odczytywanie danych wejściowych i generowanie struktury kabli) wykorzystuje tylko komórki nr 1 (które wywołam
p
) i nr 2 (które wywołamch
) i działa w pętli while w następujący sposób:Podczas warunku: zwiększaj
p
o 6, odczytaj następny znak (start plug) do komórki*p
i sprawdź, czy nie jest-1
(EOF).Wczytaj kolejne znaki
*(p+2)
i policz je*(p+1)
, aż napotkamy coś innego niż-
(łącznik). W tym momencie*(p+1)
będzie zawierać liczbę łączników (długość kabla) i*(p+2)
ostatni znak niebędący łącznikiem (wtyczka końcowa). (Kopiujemy również znaki łącznika do komórki nr 5, abyśmy mogli uzyskać dostęp do tego kodu ASCII później na etapie wyjściowym.)W pętli while znajdź wtyczkę lustra i przechowuj ją w
*(p+3)
, a następnie zwiększajp
o 2, aż*p
wyniesie zero. Pętla wygląda następująco w pseudokodzie:Ta pętla zawsze wykona dwie iteracje (wtyczkę początkową i wtyczkę końcową) i zapisze wyniki w czwartej i szóstej komórce tego kabla. Teraz, jeśli zwróciłeś uwagę, zdajesz sobie sprawę, że szósta komórka jest rzeczywiście właściwym miejscem dla lustrzanej wtyczki końcowej, ale lustrzana wtyczka początkowa znajduje się w komórce oznaczonej „boolean wskazujący oryginalny kabel”. Jest to w porządku, ponieważ potrzebujemy tylko tej komórki, aby była niezerową wartością.
Ponieważ
p
właśnie zwiększono w sumie 4, teraz wskazuje na komórkę oznaczoną „używany kabel boolowski”. Ustaw*(p+3)
na wartość*(p-1)
. To umieszcza wtyczkę lustrzanego startu we właściwym miejscu.Przeczytaj (i odrzuć) jeszcze jeden znak (który, jak się spodziewamy, będzie nową linią, ale program tego nie sprawdza).
p
początkowo zaczyna się od 0, ale zwiększa się o 6 wewnątrz warunku while, dlatego dane kabla zaczynają się od komórki nr 6.p
jest zwiększany o 4 wewnątrz korpusu pętli, a zatem w sumie 10 dla każdego kabla, co jest dokładnie tym, czego potrzebujemy.W drugim etapie, komórki # 0-4 są zajęte przez zmienne, że zadzwonię
a
,p
,q
,m
, inotdone
. (Komórka # 5 wciąż pamięta kod ASCII łącznika).Aby przygotować się do etapu 2, musimy ustawić z
*p
powrotem na 0 (komórka oznaczona jako „zero terminator”), aby mogła działać jako terminator dla listy kabli; ustawiamy takżeq
(który jest naszym wskaźnikiem stosu) nap+1
(tj. komórkę po „zerowym terminatorze”; tutaj zaczyna się stos);*q
do 1 (pierwszy przedmiot na stosie; dlaczego 1 stanie się później widoczny); inotdone
do 1. Wszystko to odbywa się w jednym oświadczeniu:Drugi etap to także pętla while. Jego stan jest po prostu
notdone
. W każdej iteracji pętli while może się zdarzyć jedna z następujących czterech rzeczy:*q
do innego kwalifikującego się kabla (który natychmiast oznaczamy jako „w użyciu” wraz z jego bliźniakiem), a następnie powrócić (tj. Utworzyć nową ramkę stosu).*q
dalej, ponieważ nie ma już innego kwalifikującego się kabla, więc musimy cofnąć się (usunąć ramkę stosu i oznaczyć poprzedni kabel i jego bliźniak jako „nieużywany”).*q
dalej, ponieważ nie ma już innego kwalifikującego się kabla i nie możemy cofnąć się, ponieważ doszliśmy do końca stosu. Oznacza to, że nie ma rozwiązania.Ciało pętli sprawdza każdy z tych czterech warunków w tej kolejności. Oto szczegóły:
Ustaw
m
ip
na 1, a następnie w pętli while zwiększajp
o 5 (w ten sposób iterując po kablach) i sprawdź, czy*(p+4)
(„w użyciu”) jest ustawione. Jeśli nie jest, ustawm
na 0. Na końcu tej pętlim
powie nam, czy wszystkie kable są w użyciu. Jeśli tak, ustaw wartośćnotdone
0, aby zakończyć główną pętlę. W przeciwnym razie przejdź do kroku 2 poniżej.Ustaw
p
na*q
(kabel u góry stosu), a po chwili pętlę podobną do powyższej zwiększajp
o 5, aby przejść przez kable. Zaczynając od,*q
gwarantujemy, że bierzemy pod uwagę tylko te, których wcześniej nie rozważaliśmy; pamiętaj jednak, że początkowa wartość dla nowej ramki stosu wynosi 1, więc pierwszym spojrzanym kablem jest ten w komórce 6, który jest rzeczywiście pierwszym kablem.Dla każdego kabla musimy sprawdzić,
*(p+4)
czy nie jest on już w użyciu, a także czy*(q-1)
ma wartość zero (co oznacza, że jesteśmy na dole stosu, więc nie ma ograniczeń na wtyczce startowej), lub*p
(początek kabla wtyczka) jest równa*(*(q-1)+2)
(wtyczka końcowa kabla tuż poniżej na stosie). Sprawdzamy równość, ustawiająca
na*(*(q-1)+2)
im
do,*p+1
a następnie zmniejszając oba w pętli while. Jest+1
tak, ponieważm
jest zmniejszane w warunku while, więc jest zmniejszane raz jeszczea
. Jeślia
na końcu jest zero, dwie wtyczki są równe.Zatem, jeśli albo
*(q-1)
było zero, albo porównanie równości się powiodło, kabel kwalifikuje się. Ustaw,*q
abyp
zastąpić kabel u góry stosu nowym; ustawm
na to samo, aby wskazać, że znaleźliśmy pasujący kabel; a następnie zmniejszeniep
. To zmniejszenie jest małą sztuczką, aby spowodować, że pętla while (iteracja po kablach) zakończy się wcześniej; zwiększyp
się ponownie o 5, przenosząc go do komórki zawierającej flagę „w użyciu” tego kabla i wiemy, że to zero, ponieważ właśnie to sprawdziliśmy. Wreszcie po iteracji kabla podczas pętli sprawdzamy, czym
nie jest zero. Jeśli tak, znaleźliśmy pasujący kabel ip
wskazuje flagę „w użyciu” dla tego pasującego kabla. Ustaw na 1, aby zaznaczyć, że jest w użyciu. Również ustawione*(*(p-1) ? p+5 : p-5)
do 1, aby zaznaczyć, że jego bliźniak jest w użyciu. Na koniec zwiększq
i ustaw nowy*q
na 1, aby utworzyć nową ramkę stosu.Jeśli po iteracji kabla podczas pętli okaże
m
się, że wynosi zero, nie ma już pasujących kabli, więc musimy cofnąć się. Zmniejszenie,q
aby przejść w dół stosu i sprawdzić, czy nadal wskazuje na kabel (wartość niezerowa). Jeśli tak, oznacz ten kabel i jego bliźniak jako nieużywany. (Przechowujemy wartość*q
in,p
aby to wyrażenie było krótsze w kodzie).Jeśli po zmniejszeniu
q
okaże się, że wskazuje on na wartość zerową, to jest to „terminator zerowy”, co oznacza, że wyczerpaliśmy stos. Stwierdzamy, że nie ma rozwiązania. Ustawiamynotdone
na 0, aby zakończyć główną pętlę.Trzeci etap to etap wyjściowy. Mogą się zdarzyć dwie rzeczy:
Wygodnie, jeśli nie było żadnego rozwiązania,
p
jest równa zero, ponieważ możemy ustawić go na wartość*q
przed sprawdzeniem, że do zera; a jeśli nie było to rozwiązanie,p
wskazuje na „zero terminatora”, ponieważ tylko powtórzyć za pośrednictwem kabli, dzięki czemu możemy teraz użyćp
iterację stosie. Więc po prostu iteruj przez stos, wyprowadzając dla każdego kabla wtyczkę początkową (*(*p)
), łączniki (zmniejszając*(*p+1)
w pętli while; i używając kodu ASCII łącznika zapisanego w komórce # 5) oraz wtyczkę końcową (*(*p+2)
). Nieważne, że to niszczy informacje o długości kabla; już tego nie potrzebujemy.źródło
CJam, 67
Wypróbuj online
Uwaga: link używa najnowszego kodu z repozytorium (wypchnięty, ale jeszcze nie wydany), ponieważ zawiera poprawkę błędu.
Wyjaśnienie:
Program po prostu wypróbowuje wszystkie permutacje i wszystkie orientacje przewodów.
źródło
(-] ]-> >-} }-) )-[ [-< <-{ {-(
.JavaScript (ES6), 206
Funkcja rekurencyjna
Bardziej czytelny
Test
źródło
JavaScript, 800 bajtów
Dalekie od zoptymalizowanego rozwiązania, ale oto szybki hack razem w javascript (bez fantazyjnego ecma5 lub czegokolwiek, ponieważ go nie znam).
Ungolfed, tutaj jest ... Jestem pewien, że co najmniej 2 pętle są tutaj niepotrzebne i że sprawdzanie wejścia pojedynczego elementu na górze i dopasowania pojedynczego elementu na dole jest dziwne ... ale wydaje się, że działa i przetwarza dane wejściowe testu.
źródło
s.charAt(x)
===s[x]
Python 3, 217 bajtów
( Demo na Ideone )
źródło
(-] ]-> >-} }-) )-[ [-< <-{ {-(
?Lua, 477 bajtów
Akceptuje przewody jako argumenty wiersza poleceń
źródło
Python 3.5,
448432427424286311 bajtów:( +25, ponieważ wystąpił błąd, w wyniku którego wyjście może być dłuższe niż powinno być dla niektórych danych wejściowych )
Działa świetnie!
z wyjątkiem danych wejściowych o 7 lub więcej wartościach. Zajmuje to dużo czasu, najprawdopodobniej dlatego, że musi przejść przez wszystkie te kombinacje wejścia plus odwrócone wejście . Spróbuję to naprawić, jeśli i kiedy będę mógł, ale na razie wydaje się to wystarczająco dobre.Teraz wszystko jest dobrze! Gdybym tylko mógł w jakiś sposób użyć tegotry-except
bloku do zrozumienia listy, mógłby być on nieco krótszy i wyglądałby znacznie ładniej. Niemniej jednak, obecnie pracuje dla wszystkich przypadków testowych, a najlepsze jest to, że używa żadnych importu! :)Wypróbuj online! (Ideone) (tutaj 284 bajty)
(Wskazówka: aby wypróbować, po prostu wybierz „widelec”, a następnie wprowadź wybrane opcje, oddzielając je spacjami i wybierz „uruchom”)
Wyjaśnienie
Zasadniczo dzieje się ...
B
jest tworzona na podstawie danych wejściowych przez podzielenie jej w spacji na składowe„ sznury ”.M
to ciąg, który utworzyłem, który po ocenie zwraca listę, na podstawieB
której zawiera wszystkie sznury, ale tym razem do tyłu .M
jest ostatecznie połączona zeB
sobą, aby utworzyć listęf
, ze wszystkimi możliwymi orientacjami „linek”.d
jest kolejna lista, która zostanie zainicjowana z pierwszą wartością (wartościąf[0]
) zf
.d
są iterowane, a ostatni znak każdej wartości jest porównywany z pierwszym znakiem każdego elementu wf
, a po znalezieniu dopasowania znak ten jest usuwany (lub usuwany) i zwracany z listyf
. Dzieje się tak, dopóki a nieIndexError
zostanie podniesione lub długość listy nied
przekroczy,B
a aNameError
zostanie wywołane po wywołaniuE
, oba są obsługiwane, a następnied
zawartość listy jest łączona w ciąg znaków i zwracana, dopóki długość listyd
jest większa dłuższa lub równa długości listyB
. W przeciwnym razie zwracany jest pusty ciąg znaków (''
), ponieważd
nie jest tej samej długości coB
oznacza, że wszystkie „sznury” na liścieB
nie można połączyć w jeden długi „sznur”.źródło
<!-- language: lang-python -->
. Co to zmienia?