Elastyczny wąż wygląda mniej więcej tak:
<||=|||:)~
Każdą oddzielną sekwencję pionowych pasków ( |
) w rozciągliwym wężu, znanym jako odcinek rozciągliwy , można indywidualnie rozciągać do dwukrotnej szerokości i rysować naprzemiennymi ukośnikami ( /
, \
) po rozciągnięciu.
Konkretny wąż powyżej ma dwie takie rozciągliwe części, co daje mu cztery możliwe pozy:
<||=|||:)~
</\/\=|||:)~
<||=/\/\/\:)~
</\/\=/\/\/\:)~
Ogólna forma rozciągliwego węża w jego najmniej rozciągniętej pozycji jest zdefiniowana przez ten regex :
<(\|+=)*\|+:\)~
Które można wyrazić słowami:
<
, Po czym przez dowolną liczbę sekwencji|
„S połączone z=
oznaczeń, a następnie:)~
.
Więc <|:)~
i <||:)~
i <|=|:)~
i <|=|=||=|||||=||:)~
są rozciągliwe węże, ale <=:)~
i <=|:)~
i <||=:)~
i <|==||:)~
nie są.
Elastyczne węże mogą również być skierowane w lewo zamiast w prawo, np ~(:|||=||>
. Formy są takie same, tylko odzwierciedlone.
Wyzwanie
Napisz program, który pobiera jeden ciąg linii dwóch rozciągliwych węży skierowanych do siebie, z pewną liczbą odstępów pomiędzy nimi. Oba węże będą w najmniej rozciągniętej pozycji (wszystkie pionowe kreski, bez ukośników). Sznurek zacznie się od ogona węża zwróconego w prawo, a skończy się ogonem węża skierowanego w lewo (możesz opcjonalnie założyć, że jest też nowa linia).
Na przykład, oto możliwe dane wejściowe z pięcioma spacjami między wężami:
<|=||:)~.....~(:||||>
.
Dla jasności używam kropek ( ) zamiast rzeczywistych znaków spacji.
Zero spacji między wężami jest również prawidłowym wejściem:
<|=||:)~~(:||||>
Mówimy, że węże całują się, gdy ich języki dotykają się w ten sposób.
Twój program musi rozszerzyć kombinację rozciągliwych części obu węży, tak aby węże miały możliwie najmniejszą liczbę odstępów między nimi (bez nakładania się), tj. Tak, aby węże były tak blisko pocałunku, jak to możliwe .
Oba ogony węży są nieruchome, ale ich głowy i ciała mogą się poruszać - w prawo w przypadku węża skierowanego w prawo, w lewo węża w lewo - w zależności od tego, jakie rozciągnięte części zostały rozciągnięte.
Dane wyjściowe twojego programu to ciąg pojedynczej linii (plus opcjonalny znak nowej linii), który pokazuje węże tak blisko pocałunku, jak to możliwe, z naprzemiennymi ukośnikami rysowanymi zamiast pionowych pasków dla rozciągniętych części, które zostały rozciągnięte.
Na przykład dane wyjściowe dla <|=||:)~.....~(:||||>
(z góry) to:
</\=||:)~~(:/\/\/\/\>
Jest to jedyne rozwiązanie tutaj, ponieważ przy każdej innej kombinacji rozciągniętych odcinków węże zachodzą na siebie lub są bardziej oddalone od całowania.
Jeśli możliwych jest wiele rozwiązań, wyjściem może być dowolne z nich.
Na przykład, jeśli dane wejściowe to
<|=||:)~.....~(:|||=|>
wyjście może być
<|=/\/\:)~~(:/\/\/\=|>
lub
</\=||:)~~(:/\/\/\=/\>
Pamiętaj, że nie zawsze będzie możliwe pocałowanie węży, ale nadal musisz zbliżyć je jak najbliżej.
Na przykład, jeśli dane wejściowe to
<||=||||:)~...~(:||>
wyjście może być
</\/\=||||:)~.~(:||>
lub
<||=||||:)~.~(:/\/\>
Jeśli węże już się całują, wyjście będzie takie samo jak wejście. na przykład
<|=||:)~~(:||||>
Ogólnie rzecz biorąc, wyjście będzie takie samo jak wejście, jeśli przedłużenie dowolnej rozciągliwej części sprawi, że węże będą się nakładać. na przykład
<|||=|||:)~..~(:||||=|||||=||||||>
Notatki
- Pobiera dane wejściowe ze standardowego wejścia lub wiersza poleceń jak zwykle lub zapisuje funkcję, która pobiera ciąg znaków. Wydrukuj lub zwróć wydruk.
- Możesz użyć kropek (
.
) na wejściu i wyjściu zamiast spacji (), jeśli wolisz.
- Ważne jest tylko, aby nacięcia były zmieniane naprzemiennie w sekwencji pionowych pasków, które zastąpiły. Ich kolejność w ogóle w wężu lub to, czy najpierw chodzi o cięcie do przodu, czy do tyłu, nie ma znaczenia.
- Rozciągliwe części nie mogą się częściowo rozciągać - są dokładnie podwójne lub w ogóle się nie rozciągają.
Punktacja
To jest golf golfowy . Najkrótsze przesłanie w bajtach wygrywa. Tiebreaker to wcześniejsza odpowiedź.
źródło
>
nie stałby się<
albo taki sam dla(
i)
), ale także powiedział: „Ważne jest tylko, aby przecinać naprzemiennie w sekwencji pionowych pasków, które zastąpiły. wąż na wolności lub to, czy najpierw nastąpi cięcie do przodu, czy do tyłu, nie ma znaczenia. ”Odpowiedzi:
CJam,
87717068 bajtówWypróbuj online w interpretatorze CJam .
Jak to działa
źródło
Retina ,
209107999792 bajtówDla celów zliczania każda linia przechodzi w osobny plik, ale możesz uruchomić kod z jednego pliku z
-s
flagą.Połączenie najlepszych cech wyrażeń regularnych .NET i Retina: równoważenie grup, szukanie dowolnych długości i wielokrotne zastępowanie wyrażeń regularnych.
Zasadniczo długi regex koduje prawidłowe rozwiązanie, a moduł cofania silnika regex znajduje dla mnie jedno z optymalnych.
Wyjaśnienie
Najpierw zastanówmy się, w jaki sposób możemy znaleźć poprawne rozwiązanie (niekoniecznie generujące poprawny wynik) za pomocą wyrażenia regularnego. Możemy użyć grup równoważących .NET, aby pomóc nam policzyć elastyczne części. Rozważ następujące prostsze wyrażenie regularne:
Możemy to wyłączyć.
To dopasowuje cały ciąg, wypychając jedno przechwytywanie na
1
stos grupy dla każdego miejsca na wejściu. Wykorzystamy ten stos, aby upewnić się, że rozciągliwe części dokładnie wypełniają przestrzeń przechwyconą w te grupy.Dalej jest spojrzenie. Chodzi o to, że w Lookout .hindhinds są dopasowywane od prawej do lewej strony (tak należy je czytać). Daje nam to możliwość powtórnego przejścia przez łańcuch, aby dowiedzieć się, czy istnieje podzbiór rozciągliwej części, która sumuje się z liczbą dopasowanych spacji. Przeglądając wygląd od prawej do lewej:
To tylko upewnienie się, że zaczynamy od końca sznurka (ogona węża).
Dla każdej rozciągliwej części, to albo dopasowuje całą część bez robienia czegokolwiek (
\|+
), albo dopasowuje całą część podczas wyskakiwania przechwytuje stos1
((?<-1>\|)*
). Taka zmiana zapewnia, że możemy w pełni rozciągnąć tylko rozciągliwą część lub pozostawić ją niezmienioną, i nie dostać takich rzeczy|/\|
. Następnie przechodzimy do następnej elastycznej części za pomocą[^|]+
.Na koniec upewniamy się, że przemierzyliśmy cały łańcuch (oba węże), a ten stos
1
jest całkowicie pusty. To znaczy, że znaleźliśmy podzbiór rozciągliwej części, która dokładnie sumuje się do liczby miejsc, które zrobiliśmy wcześniej.Cofacz będzie przechodził do przodu i do tyłu przez łańcuch, wypróbowując wszystkie kombinacje niezmienionych i rozszerzonych części, aż problem sumy podzbiorów zostanie rozwiązany. Jeśli taki podzbiór nie istnieje, szukanie nie powiedzie się. Spowoduje to, że cofający się wróci do
\S+( )+.+
części i spróbuje przechwycić o jedno miejsce mniej( )+
(co będzie tylko osłoną.+
). Ze względu na chciwość+
staramy się zatem wypełnić jak najwięcej miejsc.Możesz sprawdzić ważność tego podejścia za pomocą tej nieznacznie zmodyfikowanej substytucji:
Który da ci ciąg
=spaces=
z dokładnie taką liczbą spacji, jaką można wypełnić danymi wężami.Musiałem dodać trochę więcej sztuczek, aby faktycznie rozszerzyć poprawne
|
s. Zasadniczo chcę zastąpić wszystkie,|
które zostały dopasowane za pomocą(?<-1>\|)+
gałęzi. Chodzi o to, aby dopasować indywidualną postać, umieścić solver w otoczeniu i ustawić flagę, jeśli zdarzy się dopasowanie wewnątrz tej gałęzi. Jeśli ta flaga nie została ustawiona, unieważniamy dopasowanie na końcu, aby uniknąć zamiany innych znaków.Aby to zrobić, korzystamy z wielu zagnieżdżonych opisów. Ponownie, zmienne długości lookbeindów .NET są dopasowywane od prawej do lewej, więc jeśli zagnieżdżymy lookaheads i lookbehinds, możemy pozwolić silnikowi wyrażeń regularnych przemierzać ciąg kilka razy. Z powodów golfowych solver jest odwrócony w moim rzeczywistym rozwiązaniu (zaczynając od końca, zbierając spacje od prawej do lewej, a następnie rozwiązując sumę podzbioru od lewej do prawej), ale w przeciwnym razie struktura solvera jest dokładnie taka sama . Przeanalizujmy pełne wyrażenie regularne:
Dopasowujemy pojedynczy znak, a następnie przechwytujemy pozostałą część ciągu i przesuwamy kursor na koniec ciągu. Użyjemy tej grupy
1
później, aby sprawdzić w solverie, czy jesteśmy na pozycji meczu.To jest jak pierwsza część prostego solwera powyżej, z tym wyjątkiem, że zbieramy spacje od prawej do lewej. Cofanie liczby spacji działa dokładnie tak samo jak poprzednio, tyle że teraz używamy grupy
5
.To jest tak samo jak poprzednio, z tym wyjątkiem, że przechodzimy od lewej do prawej i za każdym razem, gdy dopasowujemy
|
aw rozwijającej się gałęzi, sprawdzamy, czy jest to ta dopasowana zTo jest opcjonalny lookahead. Próbuje
1
ponownie dopasować grupę (co tutaj jest możliwe tylko wtedy, gdy jesteśmy tuż po dopasowaniu znaku), a jeśli to zrobimy, przechwytujemy pusty ciąg do grupy4
, co wskazuje, że znaleźliśmy bieżący znak w jednym rozwiniętych bitów. Jeśli\1
nie pasuje,4
nie przechwyci niczego, a to?
gwarantuje, że nieudany lookahead w ogóle nie wpłynie na solver.Wreszcie, po zakończeniu całego rozwiązywania, sprawdzamy tylko,
\4
czy zastosowano ten lookahead. Jeśli tak, chcemy zastąpić obecną postać/\
.Pozostaje jedna trudność: usunięcie odpowiedniej ilości spacji. Najkrótszym sposobem na to, jaki do tej pory znalazłem, jest wstawienie spacji wraz z,
/\
a następnie pozbycie się jednego miejsca między językami dla każdego z tych pól znaczników w osobnym kroku:źródło
Rubin
191 187 186 170162Jest to funkcja, która pobiera ciąg jako parametr i zwraca ciąg.
Testy online: http://ideone.com/uhdfXt
Oto czytelna wersja:
W wersji golfowej główna funkcja jest odpowiednikiem
KISS
powyższej funkcji, aCOMBINATIONS
funkcja została wstawiona.źródło
<|=||:)~~(:||||>
, którego specyfikacja jest poprawnym wejściem.Python, 205 bajtów
Posiadanie pojedynczej lambdy wygląda schludnie, ale jestem prawie pewien, że nie jest to najlepsza droga. Ale publikuję to, ponieważ wszystko, co do tej pory mam, wygląda na całkiem przyzwoite.
Jest to proste brute force na wszystkich możliwych wymian
|
z/\
, filtrowanie nieprawidłowe konfiguracje. Jedynym schludny nieco Chyba jest to, że w rzeczywistości nie zastąpi każdy|
z/\
bezpośrednio - najpierw wymienić|
zX
i upuść.
od połowy do każdej wymianie, podejmują minimalna długość łańcucha w stosunku do wszystkich ważnych ciągów, a następnie zastąpićX
sz/\
.Próbowałem kilku innych podejść, w tym rekurencyjnych, ale okazały się dość nieuporządkowane. Dowiedziałem się również, że
re.split
obecnie nie dzieli się na puste ciągi, co było niefortunne, ponieważ jeden z moich pomysłów dotyczył podziału na\b
granicy słów.źródło
Mathematica, 381 bajtów
Czysta funkcja przyjmująca ciąg za argument. Oczekuje
.
raczej niżwęży.
Nie sądziłem, że będzie tak źle ... Oto, co miałem, zanim zmiażdżyłem to i naprawiłem wszystko.
Oto przykładowy przegląd z objaśnieniem:
źródło
a=StringReplace;b=StringSplit;c=StringLength;d=Total;
a następnie zastępując je w razie potrzeby w innym miejscu w środku:a=StringReplace;b=StringSplit;c=StringLength;d=Total;a[MapAt[a[#,"|"->"/\\"]&,b[#<>"="<>#2,"="],#3]~StringRiffle~"=",")="->")~"<>If[#4>0,"."~StringRepeat~#4,""]<>"~"]&[#1,#3,Sequence@@Function[{l,s},{#,#2-d@Extract[l,#]}&[Flatten[l~Position~#~Take~#2&@@@Tally@#&@@Select[Subsets@l,d@#<=s&]~MaximalBy~d,1],s]][c/@StringCases[#1<>#3,"|"..],c@#2]]&@@#~b~"~"&
Prolog (ECLiPSe), 438 bajtów
Inne moje odpowiedzi rozwiązały niewłaściwy problem (przepraszam za hałas). Oto kolejna próba w Prologu, która faktycznie przestrzega wszystkich zasad.
Testy
(format: wejście, wyjście, nowa linia)
Objaśnienia
Główny predykat to
s/2
, który przyjmuje dane wejściowe jako pierwszy argument, a wynik drugiego argumentu (oba ciągi) ujednolica wynik. Wejście jest konwertowany do listy kodów znakowychE
.Następnie
s(E,Z,X,Y,L)
rozkłada listę na następujące elementy:Z
liczba odstępów między wężamiX
orazY
abstrakcyjna reprezentacja lewego i prawego ciałaFormat treści to lista
n:N
lubs:N
wyrażenia, którychN
długość jest dodatnia;n
środkinormal
is
środkistretched
.L
całkowita długość listyInteresujące jest
s/5
to, że idzie w obie strony , tzn. Możemy zbudować węża, jeśli pojawią się inne argumenty:Q
oddzielającą nowe węże. Całkowita długość obliczonego ciągu jest ograniczona, więc wyszukiwanie kończy się.źródło
Python 2.7.3
427421400371 bajtówKod do gry w golfa tutaj -
Testowanie rozwiązania golfowego -
Z pewnością można to zrobić lepiej (nie mogę wymyślić, jak :)).
Daj mi znać, jeśli przegapiłem coś oczywistego podczas gry w golfa (to mój pierwszy codegolf, może robię coś głupiego: P)
źródło
exit
nasys.exit()
(zapomniałem, żeexit
istnieje). I masz rację,__import__
można go usunąć, który wyeliminował jak 20 znaków :)> 6
znaków, które powinny być warte aliasingu, jeśli użyjesz go dwa razy,> 3
znaków, jeśli użyjesz go trzy razy. Nie jestem pewien, czyf=' '
alias jest tego wart (liczę dwa razy)05AB1E , 93 bajty
Zbyt długo ..>.>
Wypróbuj online lub sprawdź wszystkie przypadki testowe lub sprawdź wszystkie możliwe wyniki dla wszystkich przypadków testowych .
Wyjaśnienie:
źródło