Uma máquina de estados finitos não determinística é uma máquina de estado finito, onde um tuplo é mapeado para vários estados. Ou seja. substituímos a função de transição usual δ : Q × Σ → Q de um DFA por outra função Δ : Q × Σ → P ( Q ) .
Se você sabe o que é um NFA, pode pular a próxima seção.
Definição formal
Um NFA é descrito exclusivamente por
- um conjunto finito de estados
- um conjunto finito de símbolos
- a função de transição
- o estado inicial
- um conjunto de estados finais
A máquina inicia em e lê uma sequência finita de símbolos w ∈ Σ ∗ , para cada símbolo aplicará simultaneamente a função de função de transição com um estado atual e adicionará cada novo conjunto de estados ao conjunto de estados atuais.
Desafio
Para esse desafio, ignoraremos para simplificá-lo. Além disso, o alfabeto sempre será as letras (minúsculas) de a a z e o conjunto de estados será { 0 … N para alguns não negativo inteiro N . O estado inicial será sempre 0 .
Dada a palavra e uma descrição do NFA, sua tarefa é determinar todos os estados finais.
Exemplo
Considere a cadeia e a seguinte descrição:
state, symbol, new-states
0, 'a', [1]
1, 'a', [0]
1, 'b', [1,2]
A máquina iniciará em :
- leia um : new states { 1 }
- leia a : novos estados { 1 , 2 }
- leia um : new states { 0 }
- leia um : new states { 1 }
- leia a : novos estados { 1 , 2 }
Portanto, os estados finais e, portanto, a saída seriam .
Nota: Na etapa (2), a transição do estado mapeada para ∅, pois a descrição inclui apenas transições para conjuntos não vazios.
Regras
A entrada consistirá em uma string e algum tipo de descrição do NFA (sem transições ):
- a string de entrada sempre será elemento de
- entradas válidas (não limitadas a):
- lista / matriz de tuplas / listas
- entrada separada por nova linha
- a descrição do NFA conterá apenas transições com conjuntos não vazios como resultado
- você pode abreviar regras com os mesmos caracteres se o resultado for o mesmo (por exemplo, regras
0,'a',[1,2]
e0,'b',[1,2]
pode ser abreviado com0,"ab",[1,2]
- você pode separar cada regra (por exemplo, regra
0,'a',[1,2]
pode ser0,'a',[1]
e0,'a',[2]
)
- você pode abreviar regras com os mesmos caracteres se o resultado for o mesmo (por exemplo, regras
- você pode escolher letras maiúsculas, se quiser
- você pode pegar o número de estados como entrada
- você pode assumir algum tipo de ordenação das entradas (por exemplo, ordenada por estado ou símbolos)
A saída será uma saída separada da lista / conjunto / nova linha etc. dos estados finais
- ordem não importa
- sem duplicatas (como um conjunto)
Casos de teste
Estes exemplos estarão no formato em description word -> states
que description
há uma lista de tuplas (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]
fonte
Respostas:
Haskell , 66 bytes
Experimente online!
fonte
nub
se você assumir que os estados são[Int]
, poderá usar check cada um[0..]
que é finito: 60 bytesInt
s e mais de todos os estados atuais e, portanto, ainda produz estados duplicados. Exemplo (alterado[0..]
para[0..3]
para fins de teste, mas isso não deve fazer diferença, certo?)Braquilog , 42 bytes
input as [string, nfa] onde nfa é uma lista de transições de estado [estado inicial, letra, novos estados como lista]
Explicação
Experimente online!
fonte
Brachylog v2, 31 bytes
Experimente online! ( ou com um exemplo mais complexo )
O Brachylog é realmente bom nesse tipo de problema e muito ruim em problemas que exigem duas entradas e uma saída separadas. Quase todo esse programa é apenas encanamento.
O formato de entrada é uma lista que contém dois elementos: o primeiro é a lista de transições de estado (
[oldState, symbol, newState]
) e o segundo é a lista de símbolos. Inicialmente, planejei esse programa para trabalhar com códigos de caracteres para símbolos (porque o tratamento de strings de Brachylog às vezes pode ser um pouco estranho), mas acontece que os caracteres também funcionam (embora você precise escrever a string de entrada como uma lista de caracteres, não como uma linha). Se um par de estado-símbolo pode fazer a transição para vários estados diferentes, você escreve várias transições para lidar com isso.Explicação
Provavelmente é mais fácil seguir isso, observando o que algumas versões parciais do programa produziriam. Utilizando a seguinte entrada de cada vez:
podemos observar as saídas de alguns prefixos deste programa:
Para o primeiro exemplo aqui,
L
é inicialmente um elemento desconhecido, mas quando o\
transpomos, Brachylog percebe que a única possibilidade é uma lista com o mesmo comprimento da entrada. O último exemplo aqui é não determinístico; estamos modelando o não-determinismo na NFA usando o não-determinismo no próprio Brachylog.Possíveis melhorias
Algumas das sintaxes aqui, como
↔,0↔
e principalmente a bagunçaH&hg;Hz{…ᵈ}ᵐ
, são bastante desajeitadas. Não me surpreenderia se houvesse uma maneira mais tensa de lidar com isso.{∋ᵈ}ᵐ
é uma estrutura bastante suspeita - você esperaria poder escrever∋ᵈᵐ
- mas não analisa por algum motivo.fonte
∋ᵈᵐ
não analisa porque é implementado de forma que os nomes de metapredicados com vários caracteres possam, em teoria, ser usados (se ficarmos sem possibilidades de símbolo único). Na prática, não é usado atualmente.Python 3,
10380 bytesgraças a @BWO
TIO
Compreensão de lista "elegante" anterior (103 bytes):
fonte
reduce
.. Mas o uso de conjuntos reais e de recursão ainda o reduz a 80 bytes .if''<f
porif f
.JavaScript (ES6), 99 bytes
Toma entrada como
(nfa)(string)
. Retorna um conjunto.Experimente online!
fonte
R , 81 bytes
Experimente online!
Resposta direta usando
Reduce
. Toma regras como três vetores destate, symbol, new-states
chamadoa,b,e
.As regras são separadas (por exemplo, regra
0,'a',[1,2]
é0,'a',1
e0,'a',2
).fonte
Coco , 64 bytes
Experimente online!
fonte
Limpo , 68 bytes
Este baseado na solução Haskell da ovs é um pouco menor do que minha abordagem inicial.
agora inclui um equipamento de teste
Experimente online!
fonte
Carvão , 44 bytes
Experimente online! Link é a versão detalhada do código. Explicação:
Pressione{ 0 } .
0
para a lista vazia predefinida para definir o estado inicial comoLoop sobre a entrada.
Copie o estado.
Redefina o estado.
Faça um loop sobre a cópia do estado.
Faça um loop sobre as entradas da NFA.
Se a entrada corresponder, então ...
... percorrer os novos estados ...
.... se eles ainda não estão na lista ...
... adicione-os à lista.
Transmitir a lista de estados para cadeia de caracteres para saída implícita em linhas separadas.
fonte
Perl 6 ,
6154 bytesExperimente online!
Leva uma lista de transições de estado e uma sequência de entrada como lista de caracteres.
fonte
Japonês , 31 bytes
Tente!
Economizou 2 bytes com melhor uso da capacidade do Japt de formar implicitamente uma função a partir de algumas entradas
Explicação:
O novo código "initialize states" pode usar um pouco mais de detalhes. Japt inicializa
W
a 0 se houver menos do que 3 entradas, de modo que na primeira execução[W]
é[0]
, ec
"achata" uma matriz.[0]
já é o mais plano possível, portanto não é alterado. Nas execuções subsequentes,W
tem um valor diferente, por exemplo[1,2]
. Nesse caso ,[W]
torna-se[[1,2]]
uma matriz de elemento único em que esse elemento é uma matriz. Desta vez,c
desembrulha isso e volta a[1,2]
. Assim, na primeira execução éW=[0]
e nas execuções subsequentes éW=W
.fonte