Précédent Remonter Suivant

7.3  Parcours de graphes à l'aide d'une pile

7.3.1  Parcours de labyrinthe

On se propose dans cette section de parcourir un labyrinthe que l'on aura préalablement représenté par un tableau. L'algorithme de parcours repose sur l'utilisation d'une pile.

Construction et affichage de labyrinthe

Les labyrinthes que nous allons utiliser sont des labyrinthes rectangulaires, composés de cases franchissables ou infranchissables. Les cases du bord seront toujours infranchissables sauf en haut à gauche (case de coordonnées (0,1)) et en bas à droite : ce seront les cases de départ et d'arrivée de notre labyrinthe.




Exercice 7.9 --- Affichage de labyrinthe.


Écrivez une fonction qui dessine le labyrinthe en mode texte. Pour ce faire, on définit quelques macros.
#define FERME  0
#define OUVERT 1
Vous pouvez tester cette fonction à l'aide de l'exemple suivant :
#define LONGUEUR 5
#define LARGEUR 6

char petitlab[LONGUEUR][LARGEUR] = 
  {{FERME, OUVERT, FERME, FERME, FERME, FERME},
   {FERME, OUVERT, OUVERT, OUVERT, OUVERT, FERME},
   {FERME, OUVERT, FERME, FERME, FERME, FERME},
   {FERME, OUVERT, OUVERT, OUVERT, OUVERT, FERME},
   {FERME,  FERME, FERME, FERME, OUVERT, FERME}} ;
 
L'affichage devra correspondre à :
XXXXX
    X
X X X
X X X
X X  
XXXXX

Dans la suite, on convient que la longueur sera de 70 colonnes et la largeur de 30 colonnes. De plus, ce labyrinthe sera représenté par une variable globale.




Exercice 7.10 --- Création du labyrinthe.


Écrivez une fonction qui prend en entrée la probabilité qu'une case soit franchissable et affecte aléatoirement notre labyrinthe de taille longueur×largeur. On rappelle que la fonction rand permet d'obtenir un entier aléatoire.

Cette fonction devra proposer des labyrinthes à l'utilisateur jusqu'à ce que celui-ci accepte l'un d'entre eux (n'oubliez pas de changer la graine de votre générateur d'entiers aléatoires avec la fonction srand()).

Remarquez que cette dernière fonctionnalité permet de choisir un labyrinthe qui ne soit pas trivial à résoudre.


Une pile de pas

Pour parcourir le labyrinthe, nous allons utiliser une pile de pas. Un pas correspond à 4 coordonnées : les deux coordonnées x et y du point de départ du pas et les coordonnées z et t de son point d'arrivée. La pile contiendra les pas élémentaires entre deux cases contigües à explorer ; les coordonnées de départ nous permettrons d'afficher aisément les pas.




Exercice 7.11 --- Structure de la pile.


Implantez une pile globale à l'aide d'un tableau et écrivez les fonctions classiques de manipulations de pile (empiler, dépiler, etc.).


Algorithme de parcours de labyrinthe

Pour parcourir notre labyrinthe, nous allons utiliser une variable globale représentant notre pile et qui contiendra les pas à explorer. Au début du parcours, elle ne contient que le seul pas allant de (0,1) à (1,1).

Tant que notre pile n'est pas vide, on retire le pas de tête. S'il est possible, on réaffiche le labyrinthe en prenant soin de marquer d'un signe les cases déjà visitées pour ne pas boucler. Puis on ajoute à la pile tous les pas possibles (pour lesquels la case d'arrivée est franchissable) à partir du point d'arrivée du pas considéré. Par convention, on ne se déplace pas en diagonale.

Il suffit d'itérer ce qui précède pour sortir du labyrinthe.




Exercice 7.12 --- Implantation de l'algorithme de parcours.


Implantez une fonction parcourir qui parcourt le labyrinthe selon la méthode décrite plus haut. Attention, tous les labyrinthes n'ont pas forcément une sortie !


Remarque.
Notez que le parcours ainsi obtenu n'est en rien optimal. Pour ce faire, il nous faudrait utiliser non pas une pile mais une file. L'étude de cette structure de donnée nécessite l'introduction de structure auto-référencée et dépasse le cadre de cette section (cf. 8).

7.3.2  Jeu de la lettre qui saute

Le but du jeu est de passer d'un mot à un autre par une suite de mots tels qu'un mot et le suivant ne diffèrent que d'une lettre. Par exemple, on peut passer de lion à peur par la suite de mots :
lion -> pion -> paon -> pain -> paix -> poix -> poux -> pour -> peur
Le jeu consiste à se donner deux mots et à voir s'il est possible de passer de l'un à l'autre en respectant les règles.

Nous allons modéliser ce jeu par un graphe : deux mots sont reliés s'il ne différent que d'une lettre. Une suite de mot telle que ci-dessus est donc un chemin dans le graphe. L'ensemble des mots auxquels peut mener un mot constitue une composante connexe. On peut visualiser ces définitions comme suit :

On appellera successeurs d'un mot les mots qui ne différent que d'une lettre de ce mot. Par exemple, les successeurs de lion sont pion et lien, ceux de lien sont rien, bien, sien, lieu, lier, lied, lion, tien et mien.

Pour jouer, on se propose d'utiliser le dictionnaire des mots de quatres lettres que nous avons déjà utilisé pour nous exercer aux tris :
#define taille_dico 979

/* Un dictionnaire de mots de quatre lettres */
char *dico[taille_dico] = { "drap", "nuee", "agit", "mais", "krak", "eric", 
     "aaai", "agir", "drop", "dome", "buis", "rode", "puce", "roda", "drue",
     "buse", "bure", "rode", "haie", "hais", "hait", "puer", "hall", "role",
     "halo", "haro", "puis", "hase", "decu", "pull", "vais", "puma", "haut",
     "valu", "vain", "vase", "alea", "vamp", "thon", "vaux", "vaut", "afin",
     "fier", "fief", "mica", "fiel", "thym", "fini", "midi", "epie", "meat",
     "mien", "fisc", "miel", "film", "mike", "feru", "tige", "mise", "epia",
     "tele", "fevr", "tien", "miss", "mile", "tint", "aout", "fetu", "tilt",
     "mita", "tenu", "mite", "agio", "agir", "agit", "mite", "fele", "ogre",
     "fela", "fele", "meme", "pres", "pref", "aere", "tete", "pret", "tetu",
     "hele", "hote", "here", "foin", "mode", "font", "foot", "moka", "fond",
     "fora", "fort", "toge", "todd", "mont", "mord", "mors", "fore", "mort",
     "four", "toit", "tond", "moto", "tors", "tort", "moue", "moud", "aout",
     "yvan", "tome", "tord", "mous", "yves", "tous", "toux", "flan", "tour",
     "tout", "oeil", "veau", "utah", "utah", "flou", "flot", "heur", "vend",
     "venu", "vent", "velu", "oeuf", "vers", "vert", "flux", "veto", "veuf",
     "veut", "veux", "hale", "hale", "etal", "etai", "etat", "etau", "hata",
     "hate", "ores", "have", "buee", "hate", "jusa", "hair", "etui", "aire",
     "frac", "frai", "fret", "trie", "cade", "tram", "fris", "frit", "froc",
     "cage", "cadi", "trac", "duel", "jade", "cake", "tria", "cane", "dune",
     "camp", "trio", "dura", "cafe", "troc", "mole", "came", "trot", "jais",
     "rude", "trop", "trou", "aine", "ruer", "janv", "tole", "jase", "jars",
     "jasa", "dure", "truc", "java", "jazz", "jase", "rush", "tsar", "epee",
     "clot", "aile", "aigu", "aide", "aine", "hele", "hier", "aile", "vice",
     "vecu", "aise", "aera", "hela", "vint", "viol", "aise", "visa", "vise",
     "aere", "hetu", "vive", "vite", "velo", "ange", "once", "vise", "anis",
     "anon", "onde", "anse", "ansi", "anus", "onze", "cene", "vetu", "onyx",
     "cepe", "hors", "home", "ceci", "houx", "vois", "voir", "voit", "voeu",
     "voix", "cout", "houe", "voie", "volt", "vont", "jean", "coit", "cens",
     "alfa", "cent", "allo", "vote", "vous", "cerf", "cern", "aloi", "jerk",
     "ceux", "jeun", "alto", "vlsi", "amas", "amen", "amer", "ames", "omet",
     "omis", "omit", "arcs", "caid", "oral", "orge", "vrac", "vrai", "fuel",
     "ardu", "ardt", "fuit", "chas", "char", "orme", "aria", "chef", "hote",
     "laid", "sage", "lait", "land", "muni", "tuer", "mule", "lama", "lard",
     "ores", "laps", "turc", "turf", "lame", "fuir", "chai", "chah", "sapa",
     "chat", "mure", "muer", "muet", "full", "sake", "cher", "chez", "saga",
     "saur", "oser", "chic", "tuez", "lame", "choc", "chou", "mura", "musc",
     "muse", "sain", "sais", "sait", "sana", "sang", "sans", "sali", "apex",
     "fute", "sari", "sape", "chut", "sauf", "saut", "sape", "osez", "saxo",
     "jill", "ciel", "cinq", "cime", "opus", "apre", "opte", "apte", "opta",
     "opte", "aval", "cola", "john", "lese", "jonc", "joli", "cote", "coco",
     "tres", "coke", "coin", "conf", "seau", "colt", "seme", "coma", "avec",
     "aveu", "avez", "corp", "joie", "cosy", "clip", "avis", "seme", "lest",
     "sein", "coud", "coup", "cour", "sens", "sent", "self", "sera", "serf",
     "seve", "sers", "zele", "sert", "cote", "type", "joug", "typo", "jour",
     "auto", "ubac", "ovni", "owen", "legs", "clam", "clan", "clef", "aube",
     "lent", "clin", "soul", "clos", "clou", "sema", "leur", "sept", "club",
     "seul", "type", "sexe", "sexy", "skie", "ucla", "crue", "atre", "gain",
     "huit", "gang", "hune", "gala", "gale", "naja", "html", "cote", "nain",
     "cran", "shah", "laic", "aube", "cric", "crin", "cris", "croc", "auge",
     "skia", "cone", "audy", "aune", "huer", "crut", "aura", "cote", "gant",
     "oued", "lice", "auto", "gars", "nais", "lift", "lien", "ours", "nasa",
     "lion", "sied", "nazi", "lira", "lire", "zebu", "lise", "lisp", "show",
     "zele", "lesa", "zinc", "zero", "azur", "lied", "lier", "lieu", "lino",
     "sien", "snob", "silo", "sire", "site", "lese", "oree", "gene", "sofa",
     "loin", "loir", "long", "lors", "soif", "axer", "soir", "ieee", "ayez",
     "zone", "sole", "soli", "sors", "loup", "zona", "zone", "zoom", "gout",
     "noel", "souk", "soya", "mans", "gere", "soda", "soja", "neuf", "soin",
     "soit", "ieee", "sono", "sont", "ibid", "ibis", "geai", "solo", "slip",
     "loto", "sort", "slow", "gens", "nerf", "elle", "nait", "naif", "ouie",
     "ouir", "cube", "erra", "bail", "bain", "cuir", "gata", "gate", "judo",
     "pack", "jube", "gate", "page", "juin", "pane", "quel", "jury", "jupe",
     "paon", "cure", "pars", "paru", "baba", "cuba", "paul", "gite", "watt",
     "erre", "apic", "cube", "cuis", "cuit", "banc", "bang", "jude", "quai",
     "cure", "basa", "base", "juif", "erre", "cuti", "baud", "baux", "pain",
     "pair", "paix", "quoi", "pale", "base", "jute", "parc", "pari", "part",
     "papa", "pape", "neon", "pays", "esse", "gere", "spie", "spot", "neve",
     "gena", "nier", "girl", "unir", "unit", "unix", "gera", "noce", "gond",
     "hifi", "gene", "pere", "noir", "noix", "gnon", "nord", "gene", "nous",
     "ieee", "peau", "idem", "ides", "pend", "goal", "perd", "perl", "pers",
     "peur", "peut", "ebat", "gong", "golf", "pese", "pese", "beau", "pame",
     "glas", "pale", "pama", "pame", "ilot", "pate", "pesa", "stem", "echo",
     "echu", "pate", "ecot", "swap", "ecru", "gras", "bale", "stuc", "grog",
     "gros", "urge", "bati", "daim", "luge", "atil", "race", "dame", "urne",
     "etes", "rame", "luit", "suez", "luxe", "kart", "etre", "star", "raid",
     "suce", "suif", "rail", "suis", "suit", "suiv", "rang", "luth", "rare",
     "surf", "phil", "stop", "yard", "grec", "greg", "user", "gril", "gris",
     "beat", "dada", "dais", "lune", "grue", "kaki", "pied", "dard", "pieu",
     "daze", "lune", "urge", "yack", "suer", "lump", "race", "suie", "rama",
     "rame", "rami", "rapt", "luxa", "luxe", "rave", "rata", "rate", "indu",
     "usez", "bien", "pneu", "beer", "bebe", "bile", "bise", "pige", "exil",
     "pion", "egal", "pire", "pipe", "inca", "pise", "boxe", "idee", "inne",
     "ions", "pois", "poix", "inox", "pool", "poli", "dela", "insu", "port",
     "beta", "bete", "pope", "edam", "pene", "pouf", "pour", "poux", "bock",
     "edit", "kent", "rein", "bois", "boit", "bond", "boni", "plan", "iode",
     "boom", "bord", "iode", "bouc", "boue", "boul", "bous", "bout", "poil",
     "pond", "pont", "boxa", "boxe", "polo", "iota", "porc", "pore", "yeux",
     "plut", "dent", "demi", "bleu", "blet", "rene", "lynx", "bloc", "lyre",
     "lyse", "deux", "rala", "rale", "rend", "plat", "utah", "plot", "elle",
     "suca", "bref", "irai", "imbu", "rale", "irez", "iris", "fame", "irmx",
     "guet", "pris", "prit", "prix", "imsl", "tact", "nuit", "malt", "mare",
     "mari", "taie", "tain", "bras", "tank", "taon", "talc", "ntsc", "maux",
     "bric", "brie", "item", "brio", "brin", "bris", "broc", "brou", "taux",
     "face", "unir", "fade", "fane", "irmx", "mach", "brun", "brut", "rhum",
     "deja", "faim", "mage", "fais", "fait", "fana", "fane", "unir", "faon",
     "uucp", "pole", "fard", "fart", "mail", "main", "dine", "khan", "marc",
     "mark", "mars", "isba", "faut", "dina", "faux", "dine", "tais", "tait",
     "tant", "dery", "rien", "dime", "riez", "kilt", "math", "ture", "tard",
     "reel", "tapi", "ring", "maya", "rira", "rire", "tare", "taxi", "issu",
     "dick", "rite", "defi", "dieu", "deni", "dira", "dire", "dise", "rime",
     "king", "kilo", "dito", "reer", "kiwi", "rima", "kepi", "rime", "uree",
     "dois", "donc", "rock", "rixe", "dors", "dose", "kola", "dota", "acte",
     "rond", "roll", "dose", "gres", "ivre", "rene", "dock", "fend", "roux",
     "teck", "dodu", "mens", "ment", "deca", "doit", "abat", "feue", "dont",
     "recu", "tend", "feve", "tenu", "dort", "dosa", "abbe", "meus", "meut",
     "test", "doux", "yoga", "abus", "abri", "dote", "doue", "rose", "abus",
     "elan", "roue", "mout", "fera", "rose", "ocre", "roue", "menu", "elit",
     "elis", "elle", "obus", "mess", "male", "elue", "elut", "acre", "acre",
     "acte", "emet", "emit", "emir", "emis", "emoi", "item", "oter", "emue",
     "emut" }; 
 

Représentation d'un graphe

La représentation la plus directe d'un graphe à n sommets est celle par matrice d'incidence : on utilise un tableau M de taille n× n où M[i][j] est égal à 1 s'il existe une arête entre le sommet i et le sommet j, et à 0 sinon.

Dans notre cas, les sommets correspondent à des mots. On décide de représenter chaque mot par son indice dans le dictionnaire dico. Il est donc judicieux de trier ce dictionnaire afin de pouvoir déterminer par une recherche dichotomique l'indice associé à un mot.




Exercice 7.13 --- Construction de la matrice d'incidence.


Construisez une fonction qui prenne en entrée une matrice d'incidence. Cette fonction devra construire la matrice d'incidence associée au dictionnaire défini globalement et la stocker dans la matrice d'incidence passée en argument.

Pour ce faire, on peut construire une fonction qui prend en arguments deux chaînes de caractères et qui retourne 1 s'il s'agit de successeurs et 0 sinon.


Parcours en profondeur de notre graphe

Nous pouvons maintenant aborder le jeu proprement dit. Deux mots étant donnés, il nous faut parcourir notre graphe à partir d'un sommet (premier mot) jusqu'à ce que : Cette démarche nous rappelle celle utilisée lors du parcours de labyrinthe. Nous pouvons donc utiliser le même type de solution.




Exercice 7.14 --- Parcours du graphe des mots.


À l'aide d'une pile, implanter une fonction qui prend en argument une matrice d'incidence et deux chaînes de caractères ; cette fonction retourne 1 s'il est possible de passer du premier au second en respectant les règles de notre jeu.

Pour ce faire, il nous faut convertir les mots en les indices associés qui vont représenter les sommets. Cette opération nécessite une fonction de recherche dichotomique.


Remarques :
dans cet exercice, nous n'avons pas donné le chemin existant entre deux mots. De plus, on pourrait demander de fournir toutes les composantes connexes de ce graphe.

Ce genre d'étude est facilement réalisable du moment que l'on dispose de listes chaînés ou d'arbres. Ces deux structures de données n'ont pas été abordée jusqu'à présent.





Pour tout commentaire : Alexandre Sedoglavic.
Précédent Remonter Suivant