Vérifier une solution de la Tour de Hanoi

29

Si vous ne savez pas ce qu'est la Tour de Hanoi , je vais l'expliquer brièvement: il y a trois tiges et quelques disques dont chacun a une taille différente. Au début, tous les disques se trouvent sur la première tour, dans l'ordre trié: le plus gros est en bas, le plus petit en haut. Le but est d'amener tous les disques sur la troisième tige. Cela semble facile? Voici le hic: vous ne pouvez pas placer un disque sur un disque plus petit que l'autre disque; vous ne pouvez tenir qu'un disque dans votre main à la fois pour les déplacer vers une autre tige et vous ne pouvez placer le disque que sur des tiges, pas sur la table, espèce de salaud sournois.

exemple de solution ascii:

  A      B      C
  |      |      |      
 _|_     |      |      
__|__    |      |


  A      B      C
  |      |      |      
  |      |      |      
__|__   _|_     |


  A      B      C
  |      |      |      
  |      |      |      
  |     _|_   __|__


  A      B      C
  |      |      |      
  |      |     _|_     
  |      |    __|__      

Défi

Il y a trois tiges appelées A, B et C. (Vous pouvez aussi les appeler 1,2 et 3 respectivement si cela vous aide) Au début, tous les n disques sont sur la tige A (1).

Votre défi est de vérifier une solution pour la tour de hanoi. Vous devrez vous assurer que:

  1. Au final, tous les n disques se trouvent sur la tige C (3).
  2. Pour un disque donné à un état donné, il n'y a pas de disque plus petit en dessous.
  3. Pas d'erreurs évidentes comme essayer de retirer des disques d'une tige vide ou déplacer des disques vers des tiges inexistantes.

(la solution ne doit pas être optimale.)

Contribution

Votre programme recevra deux entrées:

  1. Le nombre de disques n (un entier)
  2. Les mouvements qui sont effectués, qui seront constitués d'un ensemble de tuples de: (tour pour prendre le disque actuellement le plus haut), (tour pour prendre ce disque) où chaque tuple fait référence à un mouvement. Vous pouvez choisir comment ils sont représentés. Par exemple quelque chose comme les façons suivantes de représenter la solution pour n = 2 que j'ai dessinée ci-dessus en ascii. (Je vais utiliser le premier dans les cas de test, car il est doux pour les yeux):

    "A-> B; A-> C; B-> C"

    [("A", "B"), ("A", "C"), ("B", "C")]

    [(1,2), (1,3), (2,3)]

    "ABACBC"

    [1,2,1,3,2,3]

Sortie

  • C'est vrai, si les conditions qui peuvent être trouvées sous "défi" tiennent.

  • Faux, s'ils ne le font pas.

Cas de test:

Vrai:

n=1, "A->C"

n=1, "A->B ; B->C"

n=2, "A->B ; A->C ; B->C"

n=2, "A->C ; C->B ; A->C ; B->C"

n=2, "A->C ; A->B ; C->B ; B->A ; B->C ; A->C"

n=3, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C"

n=4, "A->B ; A->C ; B->C ; A->B ; C->A ; C->B ; A->B ; A->C ; B->C ; B->A ; C->A ; B->C ; A->B ; A->C ; B->C"

Faux:

3e proposé par @MartinEnder, 7e par @Joffan

n=1, "A->B"

n=1, "C->A"

n=2, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C"

n=2, "A->B ; A->C ; C->B"

n=2, "A->C ; A->B ; C->B ; B->A"

n=2, "A->C ; A->C"

n=3, "A->B ; A->D; A->C ; D->C ; A->C"

n=3, "A->C ; A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C"

n=3, "A->C ; A->B ; C->B ; A->B ; B->C ; B->A ; B->C ; A->C"

n=3, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; C->B"

n=4, "A->B ; A->C ; B->C ; A->B ; C->A ; C->B ; A->B ; A->C ; B->C ; B->A ; C->A ; B->C ; A->B ; A->C"

n=4, "A->B ; A->B ; A->B ; A->C ; B->C ; B->C ; B->C"

C'est le code-golf , la solution la plus courte l'emporte. Des règles et des lacunes standard s'appliquent. Pas de piles incluses.

KarlKastor
la source
Est-il également acceptable que la deuxième entrée puisse être représentée en utilisant votre méthode, mais en utilisant des chiffres au lieu de lettres (c. A=1B=2-d C=3.,,, Etc.)?
R. Kap
1
Puis-je indexer les entrées à zéro?
Rohan Jhunjhunwala
1
Est-ce correct si une erreur est lancée lorsqu'un disque est pris à partir d'une tige vide ou inexistante?
R. Kap
1
Pouvons-nous supposer qu'il n'y aura pas de non-mouvements comme A->A?
Martin Ender
2
@Kobi vous devez vérifier moving discs to nonexistant rods.donc bien sûr que oui, c'est unD
edc65

Réponses:

7

Rétine , 84 80 octets

-5 octets grâce à Martin Ender

~
 ~$'
$
ABC
{`^(.)(.*)( ~+)\1
$3$2$1
}`^(\W+)(\w)(.*)(?<=\1~+|\w)\2
$3$1$2
^AB 

Essayez-le en ligne! (plus 5 octets pour les tests ligne par ligne)

Le code simule un jeu complet.

  • L'entrée est donnée sous la forme ACABCBACBABCAC~~~.
    ~~~signifie trois disques.
  • Les quatre premières lignes convertissent l'entrée au format du jeu: ACABCBACBABCAC ~~~ ~~ ~ABC.
    Au début, la tige A a les 3 disques et les tiges B et C sont vides.
  • Ensuite, nous avons une boucle de deux étapes:
    • Prenez la première lettre de la ligne, qui indique la prochaine tige source. Trouvez cette tige, et prenez le dernier disque dedans. Retirez la lettre et déplacez le disque vers le stark (ramassez-le).
      Dans l' exemple sur, après la première étape, le texte ressemblera: ~CABCBACBABCAC ~~~ ~~ABC.
    • Dans la deuxième étape, nous trouvons la tige cible et y déplaçons le disque. Nous validons la tige est vide, ou a un disque plus grand en haut: ABCBACBABCAC ~~~ ~~AB ~C.
  • Enfin, nous confirmons que les tiges A et B sont vides - cela signifie que tous les disques sont en C (il y a un espace supplémentaire à la dernière ligne).
Kobi
la source
Wow, c'est impressionnant
Rohan Jhunjhunwala
17

Rétine , 167 165 157 150 150 123 octets

Cela ressemble totalement à un défi qui devrait être résolu avec une seule expression régulière ... (malgré l'en-tête disant "Retina", ce n'est qu'une expression régulière .NET vanille, correspondant à des entrées valides).

^(?=\D*((?=(?<3>1+))1)+)((?=A(?<1-3>.+)|B(?<1-4>.+)|C(?<1-5>.+)).(?=A.*(?!\3)(\1)|B.*(?!\4)(\1)|C.*(?!\5)(\1)).)+(?!\3|\4)1

Le format d'entrée est la liste des instructions du formulaire AB, suivie nen unaire en utilisant le chiffre 1. Il n'y a pas de séparateurs. La sortie est 1valide et 0invalide.

Essayez-le en ligne! (Les deux premiers caractères activent une suite de tests séparés par des sauts de ligne.)

Solution alternative, même nombre d'octets:

^(?=\D*((?=(?<3>1+))1)+)((?=A(?<1-3>.+)|B(?<1-4>.+)|C(?<1-5>.+)).(?=A.*(?!\3)(\1)|B.*(?!\4)(\1)|C.*(?!\5)(\1)).)+(?<-5>1)+$

Cela peut éventuellement être raccourci en utilisant 1, 11et 111au lieu de A, Bet Cje devrai y réfléchir plus tard. Il pourrait également être plus court de diviser le programme en plusieurs étapes, mais où est le défi? ;)

Explication

Cette solution fait un usage intensif des groupes d'équilibrage de .NET. Pour une explication complète, consultez mon article sur Stack Overflow , mais l'essentiel est que la capture de groupes dans .NET sont des piles, où chaque nouvelle capture pousse une autre sous-chaîne et où il est également possible de revenir à partir d'une telle pile. Cela vous permet de compter différentes quantités dans une chaîne. Dans ce cas, il nous permet d'implémenter les trois tiges directement en trois groupes de capture différents où chaque disque est représenté par une capture.

Pour déplacer les disques entre les tiges, nous utilisons une bizarrerie étrange de la (?<A-B>...)syntaxe. Normalement, cela extrait une capture de la pile Bet pousse sur la pile Ala chaîne entre cette capture éclatée et le début de ce groupe. Donc, une (?<A>a).(?<B-A>c)correspondance contre abclaisserait Avide et Bavec b(par opposition à c). Cependant, en raison des regards croisés de longueur variable .NET, il est possible que les captures de (?<A>...)et (?<B-A>...)se chevauchent. Pour une raison quelconque, si c'est le cas, l' intersection des deux groupes est poussée B. J'ai détaillé ce comportement dans la "section avancée" sur l'équilibrage des groupes dans cette réponse .

Sur le regex. Rods A, Bet Ccorrespondent à des groupes 3, 4et 5dans le regex. Commençons par initialiser la tige A:

^                 # Ensure that we start at the beginning of the input.
(?=               # Lookahead so that we don't actually move the cursor.
  \D*             # Skip all the instructions by matching non-digit characters.
  (               # For each 1 at the end of the input...
    (?=(?<3>1+))  # ...push the remainder of the string (including that 1)
                  # onto stack 3.
  1)+
)

Par exemple, si l'entrée se termine par 111, le groupe 3 / rod Acontiendra désormais la liste des captures [111, 11, 1](le haut étant à droite).

Le bit suivant du code a la structure suivante:

(
  (?=A...|B...|C...).
  (?=A...|B...|C...).
)+

Chaque itération de cette boucle traite une instruction. La première alternance tire un disque de la tige donnée (sur un groupe temporaire), la deuxième alternance met ce disque sur l'autre tige donnée. Nous verrons dans un instant comment cela fonctionne et comment nous assurer que le déménagement est valide.

Tout d'abord, retirer un disque de la tige source:

(?=
  A(?<1-3>.+)
|
  B(?<1-4>.+)
|
  C(?<1-5>.+)
)

Cela utilise le comportement étrange d'intersection de groupe que j'ai décrit ci-dessus. Notez que groupe 3, 4et 5aura toujours sous - chaînes de 1s à la fin de la chaîne dont la longueur correspond à la taille du disque. Nous utilisons maintenant (?<1-N>.+)pour extraire le disque supérieur de la pile Net pousser l'intersection de cette sous-chaîne avec la correspondance .+dans la pile 1. Étant donné que .+couvre toujours nécessairement la capture entière sautée N, nous savons que cela déplace simplement la capture.

Ensuite, nous mettons ce disque de la pile 1sur la pile correspondant à la deuxième tige:

(?=
  A.*(?!\3)(\1)
|
  B.*(?!\4)(\1)
|
  C.*(?!\5)(\1)
)

Notez que nous n'avons pas à nettoyer la pile 1, nous pouvons simplement laisser le disque là, car nous en mettrons un nouveau avant de réutiliser la pile. Cela signifie que nous pouvons éviter la (?<A-B>...)syntaxe et simplement copier la chaîne avec (\1). Pour nous assurer que le mouvement est valide, nous utilisons l'anticipation négative (?!\N). Cela garantit que, à partir de la position où nous voulons faire correspondre le disque actuel, il est impossible de faire correspondre le disque déjà sur la pile N. Cela ne peut se produire que si a) \Nne correspondra jamais car la pile est complètement vide ou b) the disc on top of stackN is larger than the one we're trying to match with\ 1`.

Enfin, tout ce qui reste est de s'assurer que a) nous avons correspondu à toutes les instructions et b) les tiges Aet Bsont vides, de sorte que tous les disques ont été déplacés C.

(?!\3|\4)1

Nous vérifions simplement que ni \3ne \4peut égaler ( ce qui est le cas que si les deux sont vides, parce que tout disque réel serait correspondre) et que nous pouvons alors correspondre à une 1sorte que nous n'omis aucune instruction.

Martin Ender
la source
14

Java "uniquement" 311 272 263 261 260 259 256 octets

39 octets innombrables enregistrés grâce à @Frozn remarquant une ancienne fonctionnalité de débogage ainsi que quelques astuces de golf intelligentes.

Version golfée

int i(int n,int[]m){int j=0,k=0,i=n;Stack<Integer>t,s[]=new Stack[3];for(;j<3;)s[j++]=new Stack();for(;i-->0;)s[0].push(i);for(;k<m.length;k+=2)if((t=s[m[k+1]]).size()>0&&s[m[k]].peek()>t.peek())return 0;else t.push(s[m[k]].pop());return s[2].size()<n?0:1;}

non golfé avec explication et jolies piles imprimées à chaque étape

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package codegolf;

/**
 *
 * @author rohan
 */
import java.util.Arrays;
import java.util.Stack;
public class CodeGolf {
    //golfed version
    int i(int n,int[]m){int j=0,k=0,i=n;Stack<Integer>[] s=new Stack[3];for(;j<3;j++)s[j]=new Stack();for(;i-->0;)s[0].push(i);for(;k<m.length;System.out.println(Arrays.toString(s)),k+=2)if(!s[m[k+1]].isEmpty()&&s[m[k]].peek()>s[m[k+1]].peek())return 0;else s[m[k+1]].push(s[m[k]].pop());return s[2].size()==n?1:0;}
    /** Ungolfed
        * 0 as falsy 1 as truthy
        * @param n the number of disks
        * @param m represents the zero indexed stacks in the form of [from,to,from,to]
        * @return 0 or 1 if the puzzle got solved, bad moves result in an exception
        */
    int h(int n, int[] m) {
        //declarations
        int j = 0, k = 0, i = n;
        //create the poles
        Stack<Integer>[] s = new Stack[3];
        for (; j < 3; j++) {
            s[j] = new Stack();
        }
        //set up the first tower using the "downto operator
        for (; i-- > 0;) {
            s[0].push(i);
        }
    //go through and perform all the moves
        for (; k < m.length; System.out.println(Arrays.toString(s)), k += 2) {
            if (!s[m[k + 1]].isEmpty() && s[m[k]].peek() > s[m[k + 1]].peek()) {
                return 0;//bad move
            } else {
                s[m[k + 1]].push(s[m[k]].pop());
            }
        }
        return s[2].size() == n ? 1 : 0;// check if all the disks are done
    }
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
    //test case
        System.out.println( new CodeGolf().h(3,new int[]{0,2,0,1,2,1,0,2,1,0,1,2,0,2})==1?"Good!":"Bad!");
    }

}

La version non golfée a une fonctionnalité où elle imprimera à quoi ressemblent les piles à chaque étape, alors ...

[[2, 1], [], [0]]
[[2], [1], [0]]
[[2], [1, 0], []]
[[], [1, 0], [2]]
[[0], [1], [2]]
[[0], [], [2, 1]]
[[], [], [2, 1, 0]]
Good!
Rohan Jhunjhunwala
la source
Que fait System.out.println(Arrays.toString(s))-il?
Frozn
Il imprimera assez les piles. Comme ça [[2,1,0], [] []]
Rohan Jhunjhunwala
Oups @Frozn qui était une fonctionnalité de débogage supprimée maintenant
Rohan Jhunjhunwala
Je sais, je me demande juste pourquoi il est là :) Vous pouvez également remplacer &&par &.
Frozn
@Frozn Je ne peux malheureusement pas remplacer cela parce que je comptais sur un comportement de court-circuit pour éviter d'essayer de jeter un œil à une pile vide. Merci pour la réduction de 39 octets
Rohan Jhunjhunwala
9

Python 2, 186 167 158 158 135 127 115 110 110 102 octets

n,m=input()
x=[range(n),[],[]]
for a,b in m:p=x[a].pop();e=x[b];e and 1/(p>e[-1]);e+=p,
if x[0]+x[1]:_

Prend entrée sur STDIN dans le format suivant:

(1,[(0,1),(1,2)])

Autrement dit, un tuple Python du nombre de disques et une liste Python de tuples de (from_rod,to_rod). Comme en Python, les parenthèses environnantes sont facultatives. Les tiges sont indexées zéro.

Par exemple, ce cas de test:

n=2; "A->B ; A->C ; B->C"

serait donné comme:

(2,[(0,1),(0,2),(1,2)])

Si la solution est valide, ne produit rien et se termine avec un code de sortie de 0. Si elle n'est pas valide, lève une exception et se termine avec un code de sortie de 1. Lève un en IndexErrorcas de déplacement vers une tige inexistante ou en essayant de retirer un disque d'un tige sans disque, a ZeroDivisionErrorsi un disque est placé sur un disque plus petit, ou NameErrors'il reste des disques sur la première ou la deuxième tige à la fin.

13 octets enregistrés grâce à @KarlKastor!

8 octets enregistrés grâce à @xnor!

Cuivre
la source
1
Le contrôle du tri de chaque pile semble trop compliqué. Ne pouvez-vous pas simplement vérifier que le disque déplacé est plus grand que le disque supérieur de la pile sur laquelle il est déplacé?
xnor
@xnor Merci, cela devrait fonctionner. L'ajouter maintenant.
Copper
5

Python 2.7, 173 158 138 138 130 127 123 octets:

r=range;a,b=input();U=[r(a,0,-1),[],[]]
for K,J in b:U[J]+=[U[K].pop()]if U[J]<[1]or U[K]<U[J]else Y
print U[-1]==r(a,0,-1)

Prend l'entrée via le stdin dans le format (<Number of Discs>,<Moves>)<Moves>est donné comme un tableau contenant des tuples correspondant à chaque mouvement, qui contiennent chacun une paire d'entiers séparés par des virgules. Par exemple, le cas de test:

n=3, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C" 

donné dans le poste serait donné comme:

(3,[(0,2),(0,1),(2,1),(0,2),(1,0),(1,2),(0,2)]) 

à mon programme. Génère un IndexErrorsi la 3e condition n'est pas remplie, a NameErrorsi la 2e condition n'est pas remplie et Falsesi la 1ère condition n'est pas remplie. Sinon, les sorties True.

R. Kap
la source
deux choses: la variable Yn'est jamais définie dans votre code (je pense que cela devrait être J) et U[J]+=[Y,[U[K].pop()]][U[J]<[1]or U[K]<U[J]]est plus courte de 3 caractères que lestmt1 if cond else stmt2
jermenkoo
@jermenkoo Eh bien, j'utilise cette Yvariable comme ça pour augmenter le NameErrorchaque fois que la 2ème condition n'est pas remplie. Si je devais changer Ypour J, le NameErrorne serait pas levé. Pour cette raison, je ne peux pas non plus le faire U[J]+=[Y,[U[K].pop()]][U[J]<[1]or U[K]<U[J]]car cela soulèverait NameError tout le temps , pas seulement lorsque la 2e condition n'est pas remplie.
R. Kap
bien, merci pour votre explication!
jermenkoo
5

VBA, 234 217 213 196 octets

Function H(N,S)
ReDim A(N)
While P<Len(S)
P=P+2:F=1*Mid(S,P-1,1):T=1*Mid(S,P,1)
E=E+(T>2):L=L+T-F
For i=1 To N
If A(i)=F Then A(i)=T:Exit For
E=E+(A(i)=T)+(i=N)
Next
Wend
H=L+9*E=2*N
End Function

Le format d'entrée pour les déplacements est une chaîne avec un nombre pair de chiffres (012). L'invocation est dans la feuille de calcul, = H ([nombre de disques], [chaîne de déplacement])

Le réseau A maintient la position de la tige des différents disques. Un mouvement met simplement à jour la première occurrence du numéro de tige "De" dans le numéro de tige "À". Si vous rencontrez d'abord un disque de tige «À», ou aucun disque de tige «De», c'est un mouvement invalide. La «valeur de tige» totale de A est maintenue en L, qui doit se terminer à 2N. Les erreurs sont accumulées sous forme de nombre négatif dans E.

Comme pour d'autres solutions, le «déplacement» d'un disque d'une tour vers la même tour n'est pas interdit. Je pourrais l'interdire pour 6 autres octets.

Résultats

Résultat de la fonction dans la première colonne (le dernier cas n = 3 est mon ajout à l'aide d'une tige supplémentaire).

TRUE    1   02
TRUE    1   0112
TRUE    2   010212
TRUE    2   02210212
TRUE    2   020121101202
TRUE    3   02012102101202
TRUE    4   010212012021010212102012010212

FALSE   1   01
FALSE   1   20
FALSE   2   02012102101202
FALSE   2   010221
FALSE   2   02012110
FALSE   2   0202
FALSE   3   0202012102101202
FALSE   3   0201210112101202
FALSE   3   02012102101221
FALSE   3   0103023212
FALSE   4   0102120120210102121020120102
FALSE   4   01010102121212
Joffan
la source
2

php, 141 octets

<?php $a=$argv;for($t=[$f=range($a[++$i],1),[],[]];($r=array_pop($t[$a[++$i]]))&&$r<(end($t[$a[++$i]])?:$r+1);)$t[$a[$i]][]=$r;echo$t[2]==$f;

Script de ligne de commande, prend l'entrée comme hauteur puis une série d'index de tableau (indexés 0), par exemple 1 0 2 ou 2 0 1 0 2 1 2 pour les cas de test les plus courts de 1 ou 2 hauteurs.
Echos 1 sur les vrais cas et rien sur les faux.
Donne 2 avis et 1 avertissement, il doit donc être exécuté dans un environnement qui les réduit au silence.

user55641
la source
1

JavaScript (ES6), 108

n=>s=>!s.some(([x,y])=>s[y][s[y].push(v=s[x].pop())-2]<v|!v,s=[[...Array(s=n)].map(_=>s--),[],[]])&s[2][n-1]

Format d'entrée: fonction avec 2 arguments

  • arg 1, numérique, nombre de sonneries
  • arg 2, tableau de chaînes, chaque chaîne 2 caractères «0», «1», «2»

Sortie: retourne 1 si ok, 0 si invalide, exception si tige inexistante

Moins golfé et expliqué

n=>a=>(
  // rods status, rod 0 full with an array n..1, rod 1 & 2 empty arrays
  s = [ [...Array(t=n)].map(_=>t--), [], [] ],
  // for each step in solution, evaluate function and stop if returns true
  err = a.some( ([x,y]) => {
    v = s[x].pop(); // pull disc from source rod
    // exception is s[x] is not defined
    if (!v) return 1; // error source rod is empty
    l = s[y].push(v); // push disc on dest rod, get number of discs in l
    // exception is s[y] is not defined
    if(s[y][l-2] < v) return 1; // error if undelying disc is smaller
  }),
  err ? 0 // return 0 if invalid move
  : s[2][n-1]; // il all moves valid, ok if the rod 2 has all the discs
)

Test Note: la première ligne de la fonction Test est nécessaire pour convertir le format d'entrée donné dans la question en l'entrée attendue par ma fonction

F=
n=>s=>!s.some(([x,y])=>s[y][s[y].push(v=s[x].pop())-2]<v|!v,s=[[...Array(s=n)].map(_=>s--),[],[]])&s[2][n-1]

Out=x=>O.textContent+=x+'\n'

Test=s=>s.split`\n`.map(r=>[+(r=r.match(/\d+|.->./g)).shift(),r.map(x=>(parseInt(x[0],36)-10)+''+(parseInt(x[3],36)-10))])
.forEach(([n,s],i)=>{
  var r
  try {
    r = F(+n)(s);
  } 
  catch (e) {
    r = 'Error invalid rod';
  }
  Out(++i+' n:'+n+' '+s+' -> '+r)
})

Out('OK')
Test(`n=1, "A->C"
n=1, "A->B ; B->C"
n=2, "A->B ; A->C ; B->C"
n=2, "A->C ; C->B ; A->C ; B->C"
n=2, "A->C ; A->B ; C->B ; B->A ; B->C ; A->C"
n=3, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C"
n=4, "A->B ; A->C ; B->C ; A->B ; C->A ; C->B ; A->B ; A->C ; B->C ; B->A ; C->A ; B->C ; A->B ; A->C ; B->C"`)

Out('\nFail')
Test( `n=1, "A->B"
n=1, "C->A"
n=2, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C"
n=2, "A->B ; A->C ; C->B"
n=2, "A->C ; A->B ; C->B ; B->A"
n=2, "A->C ; A->C"
n=3, "A->B ; A->D; A->C ; D->C ; A->C"
n=3, "A->C ; A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C"
n=3, "A->C ; A->B ; C->B ; A->B ; B->C ; B->A ; B->C ; A->C"
n=3, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; C->B"
n=4, "A->B ; A->C ; B->C ; A->B ; C->A ; C->B ; A->B ; A->C ; B->C ; B->A ; C->A ; B->C ; A->B ; A->C"
n=4, "A->B ; A->B ; A->B ; A->C ; B->C ; B->C ; B->C"`)
<pre id=O></pre>

edc65
la source