Graphe Orienté : existence chemin longueur k ?

Graphe Orienté : existence chemin longueur k ? - Algo - Programmation

Marsh Posté le 06-12-2005 à 15:05:10    

Salut,
 
Voilà je travaille sur les graphes orientés, plus précisemment sur des graphes ayant des arcs valués par des symboles. Mon graphe représente donc un automate. Chaque arc qui relie 2 sommets, a pour longueur 1.
 
Je cherche donc un algo qui permet de trouver s'il existe un chemin de longueur k (donné) entre l'état initial ( le sommet source du graphe ) et un état final de l'automate ( un sommet quelconque ). Autrement dit si l'automate permet de générer des mots de longueur k.
Le graphe représentant l'automate peut comporter un ou plusieurs cycles, ou pas du tout.
 
Connaissez vous un algo qui permet de résoudre ce problème ? Ou avez vous une idée ?
Si possible un algo qui repose sur la recherche en profondeur à partir du sommet initial.
 
Merci d'avance et @ bientot !

Reply

Marsh Posté le 06-12-2005 à 15:05:10   

Reply

Marsh Posté le 06-12-2005 à 16:01:09    

Ben tu donnes la réponse toi-même, non ? Tu fais une recherche en profondeur toute simple. Style :
 


FONCTION rechercher(k, i, etat_courant)
  SI i == k ALORS
    RENVOYER est_terminal(etat_courant)
  FINSI
 
  POUR CHAQUE etat_suivant = cible_suivante(etat_courant)
    SI rechercher(k, i+1, etat_suivant) ALORS
      RENVOYER VRAI
    FINSI
  FINPOUR
 
  RENVOYER FAUX
FINFONCTION


 
Ca revient en gros à regarder si un mot donné de longueur k sur un alphabet à une lettre unique est reconnu par l'automate non déterministe correspondant à ton graphe où toutes les lettres se confondent en une.


Message édité par Profil supprimé le 06-12-2005 à 16:02:54
Reply

Marsh Posté le 06-12-2005 à 16:21:30    

Le problème c'est que si le graphe comporte un circuit ou un arc reflexif ( un sommet pointe sur lui meme ), l'algo va tourner en rond.
 
Le problème est que cet algo ( je pense ) n'effectue pas toutes les possibilitées. Si au bout de k étapes, on est pas sur un état final, il faut revenir en arrière pour visiter le successeur suivant de l'état précédent ( s'il existe ).

Reply

Marsh Posté le 06-12-2005 à 16:42:31    

Mon programme ne boucle pas indéfiniment puisqu'il atteint une profondeur de k. De plus tous les chemins possibles sont explorés, c'est le principe du parcours en profondeur. :)
 
Il faut "penser récursivement" : ma boucle explore tous les successeurs de "etat_courant" (si on renvoie VRAI à un moment, c'est fini), donc elle explore tous les chemins possibles de longueur k à partir de l'état initial si besoin.


Message édité par Profil supprimé le 06-12-2005 à 16:45:57
Reply

Marsh Posté le 06-12-2005 à 16:45:25    

d'ou l'importance de borner la taille du mot a rechercher  
tu ne peux pas , avec ce type d'algo retrouver des mot de type ab*


---------------

Reply

Marsh Posté le 06-12-2005 à 16:55:02    

flo850 pour l'instant je ne cherche pas a trouver si un mot ab* ou abba* peut etre généré par l'automate représenter par le graphe.
 
Je cherche juste à savoir s'il peut générer des mots de longueur k.
 
( Quand j'aurai fini ce probleme, il me faudra savoir, si l'automate peut générer des mots ayant pour facteur une sous suite de symbole donnée. Par exemple on me donne la suite abba, je dois savoir si un mot du style b'abba'bba peut etre engendré par l'automate )

Reply

Marsh Posté le 06-12-2005 à 17:00:01    

Ben l'algo je te l'ai donné, je vois pas ce qu'il te faut de plus... Tu peux l'optimiser en évitant de boucler k-i fois sur le même état s'il est terminal, mais le principe du parcours en pronfondeur c'est ça, et mon algo fonctionne très bien. :)

Reply

Marsh Posté le 06-12-2005 à 17:06:18    

J'ai codé ton algo :
 

Code :
  1. /* nombre de sommet maximum */
  2. #define n_max 25
  3. typedef struct arc {
  4. char * arete; /* valeur de l'arete */
  5. int som; /* indice du sommet pointe */
  6. struct arc * suiv; /* arc suivant */
  7. } Arc;
  8. typedef Arc * listeArc;
  9. typedef struct sommet {
  10. int som; /* numero du sommet de 0 a n_max, -1 si inexistant */
  11. int etat; /* 0 -> initial, 1 -> final, 2 -> initial + final, -1 sinon */
  12. listeArc succ; /* successeurs du sommet */
  13. } Sommet;
  14. typedef struct {
  15. Sommet s[n_max]; /* tableau des sommets */
  16. int n; /* nombre de sommets au départs */
  17. int nb_som; /* nombre de sommets courants */
  18. } graphe;


 

Code :
  1. int longueur_mot(graphe g, int longueur)
  2. /* specif : retourne 1 s'il existe des mots d'une certaine longueur donnee,   */
  3. /*          0 sinon ( O() )                                                   */
  4.    int i, initial;
  5.    /* recherche de l'etat initial */
  6.    for(i = 0; i < g.n; i++)
  7.       if(g.s[i].etat == 0) initial = i;
  8.  
  9.    return longueur_rec(g, initial, longueur, 0);
  10. }


 

Code :
  1. int longueur_rec(graphe g, int x, int k, int cpt)
  2. /* specif : retourne 1 s'il existe un mot de longueur k, 0 sinon              */
  3. /*          ( O() )                                                           */
  4. {
  5.    listeArc temp = g.s[x].succ;
  6.  
  7.    if((cpt == k) && ((g.s[x].etat == 1) || (g.s[x].etat == 2)))
  8.       return 1;
  9.    while(temp != NULL)
  10.    {
  11.       if(longueur_rec(g, temp->som, k, cpt + 1) == 1)
  12.          return 1;
  13.       temp = temp->suiv;
  14.    }
  15.    return 0;
  16. }


 
Mais ca ne marche pas :/

Reply

Marsh Posté le 06-12-2005 à 17:16:24    

Dans le cas où le graphe se résume a un seul sommet qui posséede un arc reflexif, ca coince déjà ^^
 
Car il va aller sur le successeur ( donc lui meme ), il va relancer la fonction, ca va aller sur le successeur ( lui meme encore ), et il va encore relancer, et ainsi de suite ...

Reply

Marsh Posté le 06-12-2005 à 17:21:21    

Si cpt == k, il faut s'arrêter que l'état courant soit terminal ou non ! Là en effet tu as une jolie récursion infinie.
 
Je te conseille aussi de créer des "boîtes noires" du style "est_terminal()", "est_initial()"... enfin bref, faire de la programmation objet, ça me paraît être adapté à la situation.

Reply

Marsh Posté le 06-12-2005 à 17:21:21   

Reply

Marsh Posté le 06-12-2005 à 17:23:15    

bugmenot a écrit :

Dans le cas où le graphe se résume a un seul sommet qui posséede un arc reflexif, ca coince déjà ^^
 
Car il va aller sur le successeur ( donc lui meme ), il va relancer la fonction, ca va aller sur le successeur ( lui meme encore ), et il va encore relancer, et ainsi de suite ...


 


  SI i == k ALORS  
    RENVOYER est_terminal(etat_courant)  
  FINSI  


 
c'est différent de :
 


  SI i == k ET est_terminal(etat_courant) ALORS  
    RENVOYER TRUE
  FINSI

Reply

Marsh Posté le 06-12-2005 à 17:32:35    

Si cpt = k, il ne faut pas s'arreter forcément.
 
En effet, si on part de l'état initial qui ne possede dans ces successeurs qu'un sommet x, lequel x possede un arc reflexif ( et d'autres successeurs ), lorsqu'on va arriver sur x, on va revenir sur x, puis encore sur x, jusqu'a avoir cpt = k. Donc selon toi il faut s'arreter et conclure que le graphe n'engendre pas de mot de longueur k. Hors on n'aura pas visité la descendance complete de x.
 
Du coup pour résoudre le probleme, cela devient plus compliqué, et je n'y arrive pas :@

Reply

Marsh Posté le 06-12-2005 à 17:50:57    

Tu parlais d'automate dans ton premier post... Pour moi "engendrer" un mot de longueur k voulait dire "l'automate fini correspondant au graphe reconnaît le mot de longueur k". Dans ton exemple, après k itérations, si l'état sur lequel on a bouclé est terminal, alors le mot est reconnu, sinon le mot n'est pas reconnu. [:spamafote]

Reply

Marsh Posté le 06-12-2005 à 17:58:59    

Un mot de longueur k est un mot quelconque possédant k symboles.
 
Si l'état sur lequel on a bouclé n'étais pas terminal, alors il faut quand meme exploré le reste du graphe ( qui dans mon cas représente bien un automate non déterministe )

Reply

Marsh Posté le 06-12-2005 à 18:11:10    

bugmenot a écrit :

Un mot de longueur k est un mot quelconque possédant k symboles.
 
Si l'état sur lequel on a bouclé n'étais pas terminal, alors il faut quand meme exploré le reste du graphe ( qui dans mon cas représente bien un automate non déterministe )


 
Si ton graphe ne comporte qu'un sommet qui boucle sur lui même je ne vois pas ce qu'il reste à explorer... S'il comporte d'autres sommets, ils seront explorés puisque qu'à partir de chaque sommet on explore tous ses voisins et donc au final tous les états accessibles (en au plus k transitions évidemment !) puisqu'on part de l'état initial.
 
Ça me paraît quand même pas difficile à comprendre... Il faut voir que l'algorithme que j'ai décrit plus haut réalise un backtracking, c'est à dire qu'il teste si en partant du premier voisin du sommet courant, le résiduel de longueur k-1 est reconnu, sinon il regarde en partant du deuxième voisin, et ainsi de suite jusqu'à ce qu'il en trouve un à partir duquel on atteint un état terminal au bout de k-i itérations (s'il n'en trouve pas la boucle se termine et la fonction renvoie FAUX).


Message édité par Profil supprimé le 06-12-2005 à 18:27:18
Reply

Marsh Posté le 06-12-2005 à 19:20:51    

MERCIIIII A TOI alerim ! ! !
 
Tu m'as ouvert les yeux :p
 
Il me manquait juste un test dans mon code ( oublie ), du coup l'algo ne fonctionnait pas ^^
 
En effet j'ai rajouté à ton algo :
 

Code :
  1. FONCTION rechercher(k, i, etat_courant)
  2.   SI i == k ALORS
  3.     RENVOYER est_terminal(etat_courant)
  4.   FINSI
  5.   SI i > k ALORS
  6.     RENVOYER FAUX
  7.   FINSI
  8.   POUR CHAQUE etat_suivant = cible_suivante(etat_courant)
  9.     SI rechercher(k, i+1, etat_suivant) ALORS
  10.       RENVOYER VRAI
  11.     FINSI
  12.   FINPOUR
  13.   RENVOYER FAUX
  14. FINFONCTION


 
Le test si on avait depassé k.
 
VOILA en tout cas un grand merci à toi, tu as eu du courage avec moi ^^
 
Allé merci encore et @ bientot peut etre ;)

Reply

Marsh Posté le 06-12-2005 à 19:36:50    

Hum, je suis pas sûr que tu aies tout saisi si tu penses qu'il est utile de tester i > k. C'est inutile puisque pour appeler rechercher avec la valeur k+1 pour le paramètre i, il faudrait avoir passé "SI i == k ALORS" avec i == k. Or dans ce cas, on quitte la fonction donc ça n'est pas possible d'atteindre une valeur strictement supérieure à k pour i.
 
En revanche dans ton implémentation du dessus, tu ne fais pas que tester "i == k", tu testes également si l'état courant est terminal. Finalement tu as dû écrire quelque chose du style :
 


   if((cpt == k) && ((g.s[x].etat == 1) || (g.s[x].etat == 2)))  
      return 1;
 
   if (cpt > k)
      return 0;


 
qui est équivalent à :
 


   if(cpt == k) /* ou cpt >= k, mais j'aime bien être averti quand un rayon
                     cosmique modifie le déroulement de mon programme. :D */
      return (g.s[x].etat == 1) || (g.s[x].etat == 2);


 
qui fait l'économie d'un niveau de récursion.


Message édité par Profil supprimé le 06-12-2005 à 19:39:38
Reply

Marsh Posté le 06-12-2005 à 19:49:37    

Si on ne met pas le test cpt > k, cela ne marche plus.
 
En effet, pour TOUT cpt != k, on ne retournera rien avec ton premier test. Donc on arriverai directement sur la boucle while et là, la boucle peut etre infinie à cause des cycles ou arcs reflexifs ...

Reply

Marsh Posté le 06-12-2005 à 20:44:36    

Pour la complexité par contre, t'as une idée ?
 
Je pense que c'est du O(n + m) mais le parametre k a son importance quand meme
 
n = nombre de sommet
m = nombre d'arc

Reply

Marsh Posté le 06-12-2005 à 21:01:07    

bugmenot a écrit :

Donc on arriverai directement sur la boucle while et là, la boucle peut etre infinie à cause des cycles ou arcs reflexifs ...


 
Non, combien de fois faut-il le répéter... Quand cpt vaudra k, la récursion (ce que tu appelles la boucle) se terminera sauf si tu fais le test que tu as ajouté dans le if (savoir si l'état courant est terminal ou pas) et qui n'est pas au même endroit dans mon algo. Je le répète une dernière fois : mon algo est correct et ne boucle PAS indéfiniment et ta version est inutilement compliquée. :o
 
Edit: Hum j'ai lu un peu trop vite, tu parles de la boucle "while" qui pourrait être infinie ? Si ça se produit c'est un problème d'implémentation. Tu dois  récupérer la liste des sommets qui peuvent être atteints à partir du sommet courant. Cette liste est finie et tu la parcours séquentiellement, donc ta boucle while ne devrait pas pouvoir être infinie en aucun cas. Et de toutes façons dans ce cas le test cpt > k n'a absolument rien à voir avec ce problème. :D
 
Ah puis aussi :
 

Citation :

En effet, pour TOUT cpt != k, on ne retournera rien avec ton premier test.


 
Ben si cpt != k, c'est nécessairement que cpt < k, et donc on n'a pas fini. Et donc on rentre la boucle while qui elle va se terminer (puisqu'à un moment cpt vaudra k, il faut comprendre que la récursion n'est pas infinie, en aucun cas !).


Message édité par Profil supprimé le 06-12-2005 à 21:13:08
Reply

Marsh Posté le 06-12-2005 à 22:52:22    

LOOOL, on ne marque pas les sommets visités, donc si y'a un arc reflexif, on va boucler sur un somment et aucun test dans ton algo permet de palier a ce probleme.
En bref, ton algo marche si on rajoute mon test, c'est tout ca que je constate, et je trouve ca tout a fait logique !

Reply

Marsh Posté le 07-12-2005 à 00:18:35    

bugmenot a écrit :

LOOOL, on ne marque pas les sommets visités, donc si y'a un arc reflexif, on va boucler sur un somment et aucun test dans ton algo permet de palier a ce probleme.
En bref, ton algo marche si on rajoute mon test, c'est tout ca que je constate, et je trouve ca tout a fait logique !


 
Bon t'as rien compris tant pis pour toi, on pourra pas me reprocher de pas avoir essayé.
 
Ciao. :hello:

Reply

Marsh Posté le 07-12-2005 à 13:17:56    

C'est bon lol j'ai compris ^^
 
En fait quand j'avais implémenté j'ai laissé if(est_terminal) quand i == k. Au lieu de faire un return(est_terminal).
 
Ton algo marchait donc bien ^^
 
Allé merci encore :p

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed