Un automate fini non déterministe est une machine à états finis dans laquelle un tuple est mappé à plusieurs états. C'est à dire. nous remplaçons la fonction de transition δ : Q × Σ → Q habituelle d'un DFA par une autre fonction Δ : Q × Σ → P ( Q ) .
Si vous savez ce qu'est un NFA, vous pouvez ignorer la section suivante.
Définition formelle
Un NFA est uniquement décrit par
- Un ensemble fini d'états
- un ensemble fini de symboles
- la fonction de transition
- l'état initial
- un ensemble d'états finaux
La machine démarre en et lit une chaîne finie de symboles w ∈ Σ ∗ , pour chaque symbole, elle appliquera simultanément la fonction de fonction de transition avec un état actuel et ajoutera chaque nouvel ensemble d'états à l'ensemble d'états actuels.
Défi
Pour ce défi , nous ignorerons de la simplifier, en outre l'alphabet sera toujours les lettres (minuscules) a à z et l'ensemble des états sera { 0 ... N } pour un entier non négatif N . L'état initial sera toujours 0 .
Étant donné un mot et une description du NFA, votre tâche consiste à déterminer tous les états finaux.
Exemple
Considérez la chaîne et la description suivante:
state, symbol, new-states
0, 'a', [1]
1, 'a', [0]
1, 'b', [1,2]
La machine démarre en :
- lire un : nouveaux états { 1 }
- lire a : nouveaux états { 1 , 2 }
- lire un : nouveaux états { 0 }
- lire un : nouveaux états { 1 }
- lire a : nouveaux états { 1 , 2 }
Ainsi, les états finaux et donc la sortie seraient .
Remarque: à l' étape (2), la transition de l'état correspond à ∅ car la description inclut uniquement les transitions vers des ensembles non vides.
Règles
L'entrée consistera en une chaîne et une sorte de description du NFA (sans transitions ):
- la chaîne d'entrée sera toujours un élément de
- entrées valides (non limitées à):
- liste / tableau de tuples / listes
- entrée séparée par nouvelle ligne
- la description de la NFA ne contiendra que des transitions avec des ensembles non vides
- vous pouvez abréger des règles avec les mêmes caractères si leur résultat est le même (par exemple des règles
0,'a',[1,2]
et0,'b',[1,2]
pourrait être abrégé avec0,"ab",[1,2]
- vous pouvez séparer chaque règle (par exemple, la règle
0,'a',[1,2]
peut être0,'a',[1]
et0,'a',[2]
)
- vous pouvez abréger des règles avec les mêmes caractères si leur résultat est le même (par exemple des règles
- vous pouvez choisir des majuscules si vous le souhaitez
- vous pouvez prendre le nombre d'états en entrée
- vous pouvez supposer une sorte de classement des entrées (par exemple, triées par état ou symboles)
La sortie sera une sortie séparée par liste / ensemble / nouvelle ligne, etc. des états finaux
- l'ordre n'a pas d'importance
- pas de doublons (car c'est un ensemble)
Cas de test
Ces exemples seront au format description word -> states
où se description
trouve une liste de tuples (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]
Réponses:
Haskell , 66 octets
Essayez-le en ligne!
la source
nub
si vous supposez que les états sont[Int]
, alors vous pouvez utiliser check each[0..]
qui est fini: 60 octetsInt
s et sur tous les états actuels et produit donc toujours des états en double. Exemple (remplacé[0..]
par[0..3]
à des fins de test, mais cela ne devrait pas faire de différence, non?)Brachylog , 42 octets
entrée comme [chaîne, nfa] où nfa est une liste de transitions d'état [état initial, lettre, nouveaux états comme liste]
Explication
Essayez-le en ligne!
la source
Brachylog v2, 31 octets
Essayez-le en ligne! ( ou avec un exemple plus complexe )
Brachylog est vraiment bon dans ce genre de problème, et vraiment mauvais dans les problèmes qui nécessitent deux entrées séparées et une sortie. Presque tout ce programme n'est que de la plomberie.
Le format d'entrée est une liste contenant deux éléments: le premier est la liste des transitions d'états (
[oldState, symbol, newState]
), et le second est la liste des symboles. J'ai initialement prévu que ce programme fonctionne avec des codes de caractères pour les symboles (car la gestion des chaînes de Brachylog peut être un peu bizarre parfois), mais il s'avère que les caractères fonctionnent aussi (bien que vous deviez écrire la chaîne d'entrée sous forme de liste de caractères, pas comme un string). Si une paire état-symbole peut passer à plusieurs états différents, vous écrivez plusieurs transitions pour y faire face.Explication
Il est probablement plus facile de suivre cela en regardant ce que certaines versions partielles du programme produiraient. En utilisant à chaque fois l'entrée suivante:
nous pouvons observer les sorties de certains préfixes de ce programme:
Pour le premier exemple ici,
L
est initialement un élément inconnu, mais lorsque nous le transposons via\
, Brachylog se rend compte que la seule possibilité est une liste avec la même longueur que l'entrée. Le dernier exemple ici n'est pas déterministe; nous modélisons le non-déterminisme dans le NFA en utilisant le non-déterminisme dans Brachylog lui-même.Améliorations possibles
Une partie de la syntaxe ici, comme
↔,0↔
et surtout le désordre avecH&hg;Hz{…ᵈ}ᵐ
, est assez maladroite. Cela ne me surprendrait pas s'il y avait une façon plus tordue de formuler cela.{∋ᵈ}ᵐ
est en soi une structure assez suspecte - vous vous attendez à pouvoir simplement écrire∋ᵈᵐ
- mais elle n'analyse pas pour une raison quelconque.la source
∋ᵈᵐ
n'analyse pas car il est implémenté de telle sorte que les noms de méta-prédicats à plusieurs caractères pourraient en théorie être utilisés (si nous manquions de possibilités de symbole unique). En pratique, il n'est pas utilisé actuellement.Python 3,
10380 octetsmerci à @BWO
TIO
Compréhension de liste "élégante" précédente (103 octets):
la source
reduce
.. Mais l'utilisation de la récursivité et des ensembles réels vous ramène toujours à 80 octets .if''<f
parif f
.JavaScript (ES6), 99 octets
Prend l'entrée comme
(nfa)(string)
. Renvoie un ensemble.Essayez-le en ligne!
la source
R , 81 octets
Essayez-le en ligne!
Réponse simple en utilisant
Reduce
. Prend les règles comme trois vecteurs d'state, symbol, new-states
appelsa,b,e
.Les règles sont distinctes (par exemple, la règle
0,'a',[1,2]
est0,'a',1
et0,'a',2
).la source
Noix de coco , 64 octets
Essayez-le en ligne!
la source
Nettoyer , 68 octets
Celui-ci basé sur la solution Haskell d'Ovs est un peu plus court que mon approche initiale.
comprend maintenant un harnais de test
Essayez-le en ligne!
la source
Fusain , 44 octets
Essayez-le en ligne! Le lien est vers la version détaillée du code. Explication:
Appuyez{ 0 } .
0
sur la liste vide prédéfinie pour définir l'état initial surBoucle sur l'entrée.
Copiez l'état.
Réinitialisez l'état.
Faites une boucle sur la copie de l'état.
Faites une boucle sur les entrées NFA.
Si l'entrée correspond, alors ...
... boucle sur les nouveaux états ...
.... s'ils ne sont pas déjà dans la liste ...
... ajoutez-les à la liste.
Convertissez la liste des états en chaîne pour une sortie implicite sur des lignes distinctes.
la source
Perl 6 ,
6154 octetsEssayez-le en ligne!
Prend une liste de transitions d'état et une chaîne d'entrée comme liste de caractères.
la source
Japt , 31 octets
Essayez!
Enregistrement de 2 octets avec une meilleure utilisation de la capacité de Japt à former implicitement une fonction à partir de certaines entrées
Explication:
Le nouveau code "initialiser les états" pourrait utiliser un peu plus de détails. Japt initialise
W
à 0 s'il y a moins de 3 entrées, donc sur la première course[W]
est[0]
, etc
« aplatit » un tableau.[0]
est déjà aussi plat que possible, il n'est donc pas modifié. Par exemple, lors des exécutions suivantesW
, sa valeur est différente[1,2]
. Dans ce cas,[W]
devient[[1,2]]
un tableau à un élément où cet élément est un tableau. Cette fois, celac
déballe et revient[1,2]
. Ainsi, lors de la première exécution, c'estW=[0]
et lors des exécutions suivantes, c'estW=W
.la source