Niedeterministyczny skończony automat jest skończonej maszyny stanów, gdy krotka jest mapowany do wielu stanach. To znaczy. zastępujemy zwykłą funkcję przejścia DFA inną funkcją .
Jeśli wiesz, czym jest NFA, możesz pominąć następną sekcję.
Definicja formalna
NFA jest jednoznacznie opisany przez
- skończony zbiór stanów
- skończony zestaw symboli
- funkcja przejścia
- stanie początkowym
- zbiór stanów końcowych
Maszyna rozpoczyna od i czyta skończony ciąg symboli , dla każdego symbolu jednocześnie zastosuje funkcję przejścia z aktualnym stanem i doda każdy nowy zestaw stanów do zbioru stanów bieżących.
Wyzwanie
Na to wyzwanie będziemy ignorować uproszczenie go, ponadto alfabet zawsze będzie (małymi literami) litery do Z oraz zbiór stanów będzie { 0 ... N } jakiegoś nieujemną liczbą całkowitą N . Stan początkowy zawsze będzie wynosił 0 .
Biorąc pod uwagę słowo i opis NFA, Twoim zadaniem jest określenie wszystkich stanów końcowych.
Przykład
Rozważ ciąg i następujący opis:
state, symbol, new-states
0, 'a', [1]
1, 'a', [0]
1, 'b', [1,2]
Maszyna uruchomi się w :
- przeczytaj : nowe stany { 1 }
- poczytać : nowe kraje { 1 , 2 }
- przeczytaj : nowe stany { 0 }
- przeczytaj : nowe stany { 1 }
- poczytać : nowe kraje { 1 , 2 }
Zatem stany końcowe, a tym samym wynik wyniósłby .
Uwaga: W kroku (2) przejście stanu odwzorowuje na ∅, ponieważ opis obejmuje tylko przejścia do niepustych zbiorów.
Zasady
Dane wejściowe będą składać się z łańcucha i pewnego rodzaju opisu NFA (bez -transitions):
- ciąg wejściowy zawsze będzie elementem
- prawidłowe dane wejściowe (nie ograniczone do):
- lista / tablica krotek / list
- wejście oddzielone nowym wierszem
- opis NFA będzie zawierał tylko przejścia z niepustymi zestawami
- możesz skracać reguły tymi samymi znakami, jeśli ich wynik jest taki sam (np. reguły
0,'a',[1,2]
i0,'b',[1,2]
można je skracać0,"ab",[1,2]
- możesz wziąć każdą regułę osobno (np. reguła
0,'a',[1,2]
może być0,'a',[1]
i0,'a',[2]
)
- możesz skracać reguły tymi samymi znakami, jeśli ich wynik jest taki sam (np. reguły
- jeśli chcesz, możesz wybrać wielkie litery
- możesz przyjąć liczbę stanów jako dane wejściowe
- możesz założyć uporządkowanie wejść (np. uporządkowane według stanu lub symboli)
Dane wyjściowe będą oddzielonymi listami / zestawami / nowymi wierszami danymi wyjściowymi itd
- kolejność nie ma znaczenia
- bez duplikatów (ponieważ jest to zestaw)
Przypadki testowe
Te przykłady będą w formacie, w description word -> states
którym description
znajduje się lista krotek (state,symbol,new-states)
:
[] "x" -> []
[] "" -> [0]
[(0,'a',[1]),(1,'a',[0]),(1,'b',[1,2])] "abaab" -> [1,2]
[(0,'a',[1]),(1,'a',[0]),(1,'b',[1,2])] "abc" -> []
[(0,'p',[0,1]),(0,'g',[2]),(1,'c',[1]),(1,'g',[4]),(1,'p',[2]),(2,'c',[0])] "ppcg" -> [2,4]
[(0,'f',[1]),(1,'o',[1,2]),(2,'b',[3]),(3,'a',[4]),(4,'r',[0,4])] "foobar" -> [0,4]
[(0,'f',[1]),(1,'o',[1,2]),(2,'b',[3]),(3,'a',[4]),(4,'r',[0,4])] "fooooooobar" -> [0,4]
[(0,'f',[1]),(1,'o',[1,2]),(2,'b',[3]),(3,'a',[4]),(4,'r',[0,4])] "fobarfo" -> [1,2]
[(0,'f',[1]),(1,'o',[1,2]),(2,'b',[3]),(3,'a',[4]),(4,'r',[0,4])] "foobarrf" -> [1]
[(0,'d',[1,2]),(1,'u',[2]),(2,'u',[2,3]),(2,'p',[3]),(3,'p',[3])] "dup" -> [3]
[(0,'a',[0,2]),(0,'b',[3]),(1,'a',[1]),(1,'b',[1]),(2,'b',[1,4]),(4,'b',[2])] "aab" -> [3,1,4]
[(0,'a',[0,2]),(0,'b',[3]),(1,'a',[1]),(1,'b',[1]),(2,'b',[1,4]),(4,'b',[2])] "abb" -> [1,2]
Odpowiedzi:
Haskell , 66 bajtów
Wypróbuj online!
źródło
nub
jeśli przyjmujesz, że są to stany[Int]
, możesz użyć sprawdzania każdego,[0..]
który jest skończony: 60 bajtówInt
s i wszystkie bieżące stany, a zatem nadal tworzy zduplikowane stany. Przykład (zmienił[0..]
się[0..3]
dla celów testowych, ale nie powinno to mieć znaczenie, prawda?)Brachylog , 42 bajty
wprowadź jako [ciąg, nfa] gdzie nfa jest listą przejść między stanami [stan początkowy, litera, nowe stany jako lista]
Wyjaśnienie
Wypróbuj online!
źródło
Brachylog v2, 31 bajtów
Wypróbuj online! ( lub z bardziej złożonym przykładem )
Brachylog jest naprawdę dobry w tego rodzaju problemach i bardzo źle w problemach, które wymagają dwóch osobnych danych wejściowych i wyjściowych. Prawie cały ten program to tylko hydraulika.
Format wejściowy to lista zawierająca dwa elementy: pierwszy to lista przejść między stanami (
[oldState, symbol, newState]
), a drugi to lista symboli. Pierwotnie planowałem, aby ten program działał z kodami znaków dla symboli (ponieważ obsługa ciągów znaków Brachylog może być czasem trochę dziwna), ale okazuje się, że znaki też działają (chociaż musisz napisać ciąg wejściowy jako listę znaków, a nie jako ciąg). Jeśli para stan-symbol może przejść do wielu różnych stanów, piszesz wiele przejść, aby sobie z tym poradzić.Wyjaśnienie
Prawdopodobnie łatwiej jest to sprawdzić, patrząc na niektóre częściowe wersje programu. Za pomocą następujących danych wejściowych za każdym razem:
możemy obserwować wyniki niektórych prefiksów tego programu:
Pierwszy przykład tutaj
L
jest początkowo nieznanym elementem, ale kiedy transponujemy go przez\
, Brachylog zdaje sobie sprawę, że jedyną możliwością jest lista o tej samej długości co dane wejściowe. Ostatni przykład tutaj jest niedeterministyczny; modelujemy niedeterminizm w NFA za pomocą niedeterminizmu w samym Brachylogu.Możliwe ulepszenia
Część składni tutaj,
↔,0↔
a zwłaszcza bałagan zH&hg;Hz{…ᵈ}ᵐ
, jest dość niezgrabna. Nie zdziwiłoby mnie to, gdyby istniał szybszy sposób na sformułowanie tego.{∋ᵈ}ᵐ
sama w sobie jest dość podejrzaną strukturą - można by się było po prostu pisać∋ᵈᵐ
- ale z jakiegoś powodu nie analizuje.źródło
∋ᵈᵐ
nie analizuje, ponieważ jest zaimplementowany w taki sposób, że teoretycznie można zastosować wieloznakowe nazwy meta-predykatów (jeśli zabraknie możliwości pojedynczego symbolu). W praktyce nie jest obecnie używany.Python 3,
10380 bajtówdzięki @BWO
TIO
Poprzednie „eleganckie” zestawienie listy (103 bajty):
źródło
reduce
.. Ale użycie rekurencji i rzeczywistych zestawów wciąż sprowadza cię do 80 bajtów .if''<f
jeif f
.JavaScript (ES6), 99 bajtów
Pobiera dane wejściowe jako
(nfa)(string)
. Zwraca zestaw.Wypróbuj online!
źródło
R , 81 bajtów
Wypróbuj online!
Prosta odpowiedź przy użyciu
Reduce
. Przyjmuje reguły jako trzy wektorystate, symbol, new-states
nazywanea,b,e
.Reguły są osobne (np. Reguła
0,'a',[1,2]
jest0,'a',1
i0,'a',2
).źródło
Kokos , 64 bajty
Wypróbuj online!
źródło
Czysty , 68 bajtów
Ten oparty na rozwiązaniu ovas Haskell jest nieco krótszy niż moje początkowe podejście.
teraz zawiera uprząż testową
Wypróbuj online!
źródło
Węgiel drzewny , 44 bajty
Wypróbuj online! Link jest do pełnej wersji kodu. Wyjaśnienie:
Naciśnij przycisk{ 0 } .
0
do wstępnie zdefiniowanej pustej listy, aby ustawić stan początkowy naPętla nad wejściem.
Skopiuj stan.
Zresetuj stan.
Pętla nad kopią stanu.
Pętla nad wpisami NFA.
Jeśli wpis pasuje, to ...
... zapętlać nowe stany ...
.... jeśli nie ma ich na liście ...
... dodaj je do listy.
Rzuć listę stanów na ciąg znaków, aby uzyskać niejawne dane wyjściowe w osobnych wierszach.
źródło
Perl 6 ,
6154 bajtówWypróbuj online!
Pobiera listę przejść stanu i ciąg wejściowy jako listę znaków.
źródło
Japt , 31 bajtów
Spróbuj!
Zaoszczędzono 2 bajty dzięki lepszemu wykorzystaniu zdolności Japt do niejawnego utworzenia funkcji z niektórych danych wejściowych
Wyjaśnienie:
Nowy kod „stanów inicjalizacji” może zawierać nieco więcej szczegółów. Japt inicjuje się
W
na 0, jeśli jest mniej niż 3 wejścia, więc przy pierwszym uruchomieniu[W]
jest[0]
ic
„spłaszcza” tablicę.[0]
jest już tak płaski, jak się robi, więc się nie zmienia. Na przykład w kolejnych cyklachW
ma inną wartość[1,2]
. W takim przypadku[W]
staje[[1,2]]
się tablicą jednoelementową, której elementem jest tablica. Tym razem toc
rozpakowuje i wraca do[1,2]
. Tak więc przy pierwszym uruchomieniu jest,W=[0]
a przy kolejnych uruchomieniach jestW=W
.źródło