Dijkstra

Fermé
noussa90 - 17 avril 2013 à 05:01
KX Messages postés 16752 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 août 2024 - 18 juil. 2013 à 20:52
Bonsoir,

Pouvez vous m'aider dans l'implémentation de l'algorithme de Dijkstra (en Java). J'ai déjà commencé le travail mais je bloque sur l'affichage de la distance du plus cours chemin entre deux noeuds du graphe.




public class InputGraph {

public int [][] arc; // Matrice d'adjacense
public Object [] sommet; //objet sommet

public static int count;

public InputGraph (int n){
arc = new int[n][n];
sommet = new Object[n];

}
public int GetSize (){ // récupère la taille du sommet
return sommet.length;

}

public void SetSommet(int node, Object label){ //permet d'ajouter un sommet
sommet[node]=label;

}

public Object GetSommet(int node){ // récupère la valeur d'un sommet
return sommet[node];

}


public void AddArc(int SommetDep, int SommetArr, int dist){ // ajoute un arc
arc [SommetDep][SommetArr]=dist;

}

public int GetPoids(int SommetDep, int SommetArr){ //récupère la distance
return arc [SommetDep][SommetArr];

}




public void AfficheMatrice(){ //affiche la matrice du graphe

for (int j = 0; j < arc.length; j++) {
System.out.println("");
System.out.println( " DE " + sommet[j] +" jusqu'à ");
System.out.println("");
for (int i = 0; i < arc[j].length; i++) {
if (arc[j][i]>0)
System.out.println(sommet[i] + " la distance est de " +arc[j][i] );
}
}

}
public int [] ChercheVoisin(int node){ //construit un tableau des sommets adjacents d'un sommet

count=0;

for (int i = 0; i < arc[node].length; i++) {
if (arc[node][i]>0 ) {count ++; }
}
final int[]rep = new int [count];

count=0;
for (int i = 0; i < arc[node].length; i++){
if(arc[node][i]>0){rep[count++]=i;}
}
return rep;
}

public static void main(String[] args) {

InputGraph ex = new InputGraph (4);
ex.SetSommet(0, "processus");
ex.SetSommet(1, "phase");
ex.SetSommet(2, "activité");
ex.SetSommet(3, "label");
ex.AddArc(0, 1, 400);
ex.AddArc(0, 2, 200);
ex.AddArc(1, 2, 300);
ex.AddArc(2, 1, 100);
ex.AddArc(1, 3, 100);
ex.AddArc(2, 3, 500);
ex.AddArc(2, 0, 200);

ex.AfficheMatrice();


}
}
==========================================================

public class Dijkstra {


public static int [] djikstra (InputGraph IG, int Source){

final int [] distancecc = new int [IG.GetSize()];
final int [] pred = new int [IG.GetSize()];
final boolean [] marque = new boolean [IG.GetSize()];

for (int i = 0; i < distancecc.length; i++) {
distancecc[i]=Integer.MAX_VALUE;
}
distancecc[Source]=0;

for (int i = 0; i < distancecc.length; i++) {

final int U=ExtraireMin (distancecc, marque);
marque[U]=true;

final int [] V= IG.ChercheVoisin(U);
for (int j = 0; j < V.length; j++) {
final int NV = V [j];
final int d = distancecc[U] + IG.GetPoids(U, NV);
if (d < distancecc[NV]) {
distancecc[NV]=d;
pred[NV]=U;
}
}

}

return pred;

}


==========================================================
public class ExtraireMin {

public static int ExtraireMin(int [] distancecc, boolean [] marque){
int x =Integer.MAX_VALUE;
int y=0;

for (int i = 0; i < distancecc.length; i++) {
if (!marque[i] && distancecc[i]< x) {

y=i;
x=distancecc[i];

}

}

return y;
}
}

18 réponses

KX Messages postés 16752 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 août 2024 3 019
17 avril 2013 à 19:20
Il faut utiliser l'algorithme de Dijkstra pour calculer le tableau des prédécesseurs et s'en servir récursivement pour aller de la fin recherchée vers le début.

Voici comment on pourrait faire un tel affichage, avec le code que tu as déjà fait :

private static void aff(InputGraph graph, int[] pred, int deb, int cur)
{
    if (cur == deb)
        System.out.print(graph.sommet[cur]);
    else
    {
        aff(graph,pred,deb,pred[cur]);
        System.out.print(" --> "+graph.sommet[cur]);
    }
}
	
public static void afficherPlusCourtChemin(InputGraph graph,int debut, int fin)
{
    aff(graph,Dijkstra.djikstra(graph, debut),debut,fin);
}

Exemple dans ton main : afficherPlusCourtChemin(ex,0,3);

Ce qui donne : "processus --> activité --> phase --> label"
0
Bonsoir,

Merci KO pour votre réponse mais en sortie je veux un chiffre qui représente le chemin le plus court.

Cordialement
0
KX Messages postés 16752 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 août 2024 3 019
18 avril 2013 à 05:49
"un chiffre qui représente le chemin le plus court"
Je ne vois pas comment un chiffre pourrait représenter un chemin, mais avec ma méthode tu obtiens le chemin le plus court, donc modifies là pour obtenir ce que tu veux...
0
En fait par chiffre je veux dire la somme des poids qui sépare un noeud x à un noeud y en suivant le plus court chemin.
0
KX Messages postés 16752 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 août 2024 3 019
18 avril 2013 à 18:26
Comme je te l'ai dit ce matin, ma méthode permet d'obtenir le chemin, il faut donc l'adapter pour qu'au lieu d'un affichage elle renvoie le résultat que tu veux, mais la structure est similaire :

private static int len(InputGraph graph, int[] pred, int deb, int s)
{
    if (s == deb)
        return 0;
    else
        return len(graph,pred,deb,pred[s]) + graph.GetPoids(pred[s], s);
}

public static int longueurPlusCourtChemin(InputGraph graph,int debut, int fin)
{        
    return len(graph,Dijkstra.djikstra(graph, debut),debut,fin);
}

int longueur = longueurPlusCourtChemin(ex,0,3); // 400
0
Merci beaucoup KX. C'est très gentil de votre part.
0
Bonjour ,

Quelqu'un pourriez me dire SVP comment retrouver la profondeur d'un noeud x avec le code que j'ai déjà posté.

Cordialement.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Bonjour tout le monde,

Une question SVP, comment puis-je déterminer le poids entre deux noeuds voisins dans un graphe non orienté et en utilisant Dijkstra (le graphe et l'algorithme de Dijkstra sont déjà définis plus haut).

Merci à vous.
0
KX Messages postés 16752 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 août 2024 3 019
3 juil. 2013 à 17:54
Je ne comprends pas ce que tu appelles le poids entre deux noeuds. Je vois bien ce qu'est le poids d'un noeud, ou le poids d'une arete, mais le poids entre deux noeuds, il va falloir expliquer ce que tu entends par là.
De plus, je ne comprends pas ce que Dijkstra viendrait faire ici puisque les deux noeuds sont voisins...
0
Par poids entre deux noeuds, je veux dire le poids des arêtes qui les séparent. Je m'explique, moi je veux déterminer la proximité sémantique entre deux noeuds quelconque. Pour y arriver, j'ai attribuer des poids aux arêtes. Plus la distance qui sépare les deux noeuds est minimale, plus ces deux noeuds ( concepts dans l'ontologie) se rapprochent sémantiquement, d'ou l'intérêt de Dijkstra (parcourir le chemin minimal). Cependant, il arrive que deux noeuds soient dans le voisinage. C'est ici que je bloque pour déterminer le poids.
0
KX Messages postés 16752 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 août 2024 3 019
3 juil. 2013 à 18:36
C'est quoi ta définition de voisinage ? Pour moi deux noeuds voisins ça voulait dire liés par une même arête (donc en récupérer le poids était immédiat), de toute évidence on parle ici d'un voisinage plus large...
Ce que tu voudrais faire c'est calculer le cumul des poids des arêtes du plus court chemin ?
0
Pour moi, deux noeuds liés par une même arête, appartiennent à la même hiérarchie. Par contre, par voisinage je parle de deux noeuds X et Y qui ne sont pas sur la même hiérarchie (ces deux noeuds qui ont forcément un noeud père en commun). Ce que je veux c'est de déterminer le poids entre X et Y.
0
KX Messages postés 16752 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 août 2024 3 019
3 juil. 2013 à 21:03
C'est quoi "un noeud père commun" ?
Ton graphe est non-orienté, donc si X et Y sont sur la même composante connexe, tous les noeuds de cette composante (donc potentiellement tous les noeuds du graphe) seront sur ton voisinage.

Pour le poids entre X et Y, il faudrait effectivement un algorithme de plus court chemin pour passer de noeuds en noeuds, mais je ne suis pas sûr que le cumul doivent se faire par somme, je verrais plutôt un produit de pourcentages, mais je n'ai pas d'éléments qui me permettent de dire que c'est effectivement ça que tu fais...

Voici un exemple de graphe à pourcentages :
Le chemin A-B-C par exemple aurait un poids de 56% obtenu par produit des deux poids A-B et B-C. Vu ce que tu veux faire c'est plus cohérent qu'une somme...

Par contre il faudrait faire une adaptation du graphe pour que représenter tes poids en pourcentage où deux noeuds sont proches s'ils ont un poids d'arêtes élevés. Et une adaptation de l'algorithme pour avoir un calcul de plus long chemin; avec un cumul multiplicatif et non plus additif.

Exemple : entre D et E le chemin D-E est de 60%, le chemin D-A-E de 72% (donc c'est mieux), mais le meilleur chemin c'est D-C-A-E avec 77%.
0
Ce que je veux c'est de retrouver le poids entre D et B (si je suis votre graphe) et ce ci en suivant le plus court chemin. Dans mon travail, plus deux noeuds aient un poids faible, plus ils sont similaires sémantiquement, c'est pourquoi j'utilise Dijkstra.
0
KX Messages postés 16752 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 août 2024 3 019
4 juil. 2013 à 08:50
Le problème que j'essayais de montrer c'est que quand tu passes d'un noeud à un autre, tu dois cumuler le poids des arêtes.
Dans un algorithme de Dijkstra classique, ce cumul se fait en additionnant le poids des deux arêtes, or je doute que dans ton cas une somme soit vraiment pertinente, parce que le cumul des distances sémantiques ne serait plus réaliste.
C'est pour ça que je t'ai présenté un graphe avec des pourcentages sur les arêtes, pour permettre de faire un cumul avec des produits, mais cela nécessite d'inverser le problème et de faire un calcul de plus long chemin sur des arêtes où la similarité se fait avec un poids fort (sinon le produit donnerait un résultat incohérent).
Mais ça reste un algorithme de Dijkstra, on l'adapte juste à ton problème pour que le résultat corresponde à ce que l'on attend...
0
Bonjour,

En fait pour calculer la distance sémantique entre deux noeuds, j'ai une formule à appliquer (ce n'est pas simplement une somme des poids). Cependant, une partie de la formule consiste à chercher le chemin minimal entre ces deux noeuds.
0
KX Messages postés 16752 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 août 2024 3 019
4 juil. 2013 à 10:09
Pour calculer la distance entre les noeuds, tu as besoin du chemin minimal, donc de la distance entre les noeuds !? Tu tournes en rond...
0
Pourquoi que je tourne en rond! Pour moi, l'algorithme de Dijkstra marche très bien pour deux noeuds qui sont sur la même hiérarchie mais il bloque pour deux noeuds voisins (qui ont un noeud subsompant en commun). Par exemple: Le noeud A est connecté à B. B est connecté à C et D ( C et D sont des feuilles). Dijkstra bloque pour retrouver le chemin entre C et D. Vous me comprenez ?
0
KX Messages postés 16752 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 août 2024 3 019
4 juil. 2013 à 19:07
"pour calculer la distance sémantique entre deux noeuds, (...) une partie de la formule consiste à chercher le chemin minimal entre ces deux noeuds."

Tu tournes en rond si tu cherches à déterminer le poids d'une arête en fonction d'autres poids d'arêtes (le chemin minimal) qui dépendront eux même de l'arête que tu essayes de calculer.

Exemple : X dépend de Y et Z, avec Y qui dépend de X et Z, et Z qui dépend de X et Y, ce n'est pas possible ! Ou alors il faudrait faire un calcul d'une complexité extrême, largement au dessus de ton niveau, ce qui me fait plutôt penser que tu es mal parti dans ton raisonnement et qu'une manière plus simple de concevoir le problème existe.
0
Comment faire à votre avis ? Je ne peux pas tout de même utiliser des pourcentages pour représenter les poids parce que je me base sur le réseau sémantique Wordnet.
0
KX Messages postés 16752 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 août 2024 3 019
Modifié par KX le 4/07/2013 à 19:31
Je ne vois pas ce qui t'empêche d'utiliser un pourcentage...

Il suffit d'une simple formule de mathématiques élémentaires pour passer d'une distance à un pourcentage. Il suffit de considérer un intervalle [min,max] de tes distances (selon ta métrique), pour les faire coïncider aux 0% et 100% et échelonner les distances intermédiaires.

if (distance<min)
    pourcentage = 1.0;
else if (distance>max)
    pourcentage = 0.0;
else
    pourcentage = 1.0 - (distance - min)/(max - min);

Note : idéalement min=0, et max serait la plus grande grande distance possible. Çà permet de donner plus de sens aux pourcentages (et de simplifier le code au passage).

pourcentage = 1.0 - distance / max;
Par exemple si tes distances étaient issus d'un calcul de similarité cosinus, on aurait max = π
0
Non je vais pas utiliser une mesure de similarité déjà existante. Je vais définir une nouvelle. Pour deux noeuds quelconque, elle est donnée comme suit: 1-( poids/ 2*depth). Je ne vois pas toujours l'utilité des pourcentages.
0
KX Messages postés 16752 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 août 2024 3 019
4 juil. 2013 à 20:43
La similarité cosinus n'était qu'un exemple, de toute façon elle ne s'applique pas à la sémantique.

Les pourcentages permettent de faire un cumul multiplicatif, alors qu'avec tes distances tu es contraint d'utiliser un cumul additif ce qui va te donner des valeurs bizarres.

Je reprends le même graphe mais avec des distances (min=0, max=20)
Si on prends A, B, C, avec un cumul additif on se retrouve avec A-B qui a le même poids (6) que A-C-B, alors qu'avec les pourcentages on avait 70% et 72%, donc c'est sensiblement la même chose pour une arête.

Le problème vient quand on met les arêtes bout à bout alors on se retrouve avec des distances aberrantes, par exemple E-D-A-B-C a une distance de 22 ce qui correspond à un pourcentage négatif (-10%) ce qui n'a aucun sens !
Alors qu'avec les pourcentages on aurait une similarité certes faible (27%) mais qui reste toujours cohérente...
0
Les poids entre les noeuds de mon graphe varient de 0 à 1, donc je vais pas me retrouver dans cette situation aberrante. Ce que je veux c'est simplement de faire le cumul des poids.
0
KX Messages postés 16752 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 août 2024 3 019
5 juil. 2013 à 09:30
Les poids entre tes noeuds varient de 0 à 1, donc si par exemple tu as trois arêtes avec 0.5, tu vas te retrouver avec une somme des distances à 1.5 qui ne sera plus enre 0 et 1, ce n'est donc pas logique !
Alors qu'avec des pourcentages tu aurais juste à faire "pourcentage=1-distance" et au lieu de faire une somme tu ferais un produit, donc 0.5*0.5*0.5=0.125, ce qui correspond à une distance de 0.875 qui elle est bien entre 0 et 1...
0
J'ai déjà normalisé ma formule, donc le résultat va toujours être compris entre 0 et 1. En fait, j'ai divisé la somme des poids (chemin du noeud x au noeud y en suivant le plus court chemin) par 2* profondeur du noeud le plus éloigné de la racine.
0
KX Messages postés 16752 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 août 2024 3 019
18 juil. 2013 à 18:28
Cependant, tu pourras quand même faire des sommes et obtenir des chemins qui sont supérieurs à 1, d'où l'intérêt de la multiplication entre 0 et 1 qui elle aura toujours un résultat entre 0 et 1, jamais plus !

"profondeur du noeud le plus éloigné de la racine", que vient faire une racine là dedans ?
0
Non jamais des résultats supérieurs à 1 avec une formule comme 1-(poids/2*profondeur). Par "profondeur du noeud le plus éloigné de la racine", je veux dire le noeud ayant la profondeur la plus grande.
0
KX Messages postés 16752 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 août 2024 3 019
18 juil. 2013 à 18:57
Un noeud n'a pas de profondeur dans un graphe, ça n'a pas de sens !

Et même si tu as "1-(poids/2*profondeur)" pour un arc, ce qui est faux au passage car ça devrait être "1-poids/(2*profondeur)", et bien quand tu as deux arcs tu vas calculer le poids de ton chemin en faisant une somme 1-poids/(2*profondeur)+1-poids/(2*profondeur), et là il est tout à fait possible d'avoir un nombre supérieur à 1, ce qui est faux, alors qu'avec un produit tu n'auras pas le problème, en plus comme il faut prendre les plus grandes valeurs ça t'enlève ce "1-" en ne faisant donc plus que : poids/(2*profondeur)*poids/(2*profondeur) qui est toujours entre 0 et 1, quelque soit le nombre d'opérandes...
0
Non, vous m'avez mal compris. Dans ma nouvelle approche, plus deux concepts se rapprochent sémantiquement, moins est la distance; c'est pourquoi j'ai noté le "1-".
0
KX Messages postés 16752 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 août 2024 3 019
18 juil. 2013 à 20:52
Oui, mais je me répète, encore et encore, pour faire un cumul multiplicatif il est nécessaire que les valeurs soient proches de 1, sinon tu aurais le contraire de ce que tu veux !

Je reprends un exemple tout simple :

Tu as une distance de 0.60, ça revient à 40% de similarité, avec un cumul additif : 0.60+0.60=1.20 c'est supérieur à 1 donc ce n'est pas cohérent, alors qu'avec un cumul multiplicatif : 40%*40%=16% soit une distance de 0.84 qui est bien inférieur à 1, dans tous les cas.
0