web-dev-qa-db-fra.com

Algorithme de Dijkstra avec des poids négatifs

Peut-on utiliser l'algorithme de Dijkstra avec des poids négatifs?

ARRÊTEZ! Avant que tu penses "lol nub tu peux juste aller sans cesse entre deux points et avoir un chemin infiniment pas cher", je pense plus aux chemins à sens unique.

Une application pour cela serait un terrain montagneux avec des points dessus. Évidemment, aller de haut en bas ne prend pas d'énergie, en fait, cela génère de l'énergie (donc un poids de trajectoire négatif)! Mais revenir en arrière ne fonctionnerait pas comme ça, à moins que vous ne soyez Chuck Norris.

Je pensais augmenter le poids de tous les points jusqu'à ce qu'ils soient non négatifs, mais je ne suis pas sûr que cela fonctionne.

33
orlp

Tant que le graphique ne contient pas de cycle négatif (un cycle dirigé dont les poids des arêtes ont une somme négative), il aura le plus court chemin entre deux points quelconques, mais l'algorithme de Dijkstra n'est pas conçu pour les trouver. L'algorithme le plus connu pour rechercher les chemins les plus courts d'une source unique dans un graphe dirigé avec des pondérations de bord négatives est l'algorithme algorithme de Bellman-Ford . Cela a toutefois un coût: Bellman-Ford nécessite O (| V | · | E |), alors que Dijkstra nécessite O (| E | + | V | log | V |), lequel est asymptotiquement plus rapide pour les graphes clairsemés (où E est O (| V |)) et les graphes denses (où E est O (| V | ^ 2)).

Dans votre exemple de terrain montagneux (nécessairement un { graphe dirigé , puisque monter et descendre d'une pente ont des poids différents), il n'y a aucune possibilité d'un cycle négatif, car cela impliquerait de laisser un point puis de revenir à avec un gain d’énergie net - qui pourrait être utilisé pour créer une machine à mouvement perpétuel .

Augmenter tous les poids d'une valeur constante afin qu'ils soient non négatifs ne fonctionnera pas. Pour voir cela, considérons le graphique où se trouvent deux chemins de A à B, l'un traversant un seul bord de longueur 2 et l'autre traversant les bords de longueur 1, 1 et -2. Le second chemin est plus court, mais si vous augmentez tous les poids de bord de 2, le premier chemin a maintenant une longueur de 4 et le second chemin a une longueur de 6, inversant le chemin le plus court. Cette tactique ne fonctionnera que si tous les chemins possibles entre les deux points utilisent le même nombre d'arêtes.

57
D Coetzee

Si vous lisez la preuve de l'optimalité, l'une des hypothèses retenues est que tous les poids sont non négatifs. Donc, non. Comme le recommande Bart, utilisez Bellman-Ford s'il n'y a pas de cycle négatif dans votre graphique.

Vous devez comprendre qu'un bord négatif n'est pas simplement un nombre négatif - cela implique une réduction du coût du chemin. Si vous ajoutez un bord négatif à votre chemin, vous aurez réduit le coût du chemin --- si vous augmentez les poids de sorte que ce bord soit maintenant non négatif, il n'a plus cette propriété de réduction c'est un graphique différent.

Je vous encourage à lire la preuve de l'optimalité - vous verrez que l'hypothèse selon laquelle l'ajout d'un Edge à un chemin existant ne peut qu'augmenter (ou ne pas affecter) le coût du chemin est critique. 

3
Jacob

Il existe en fait un algorithme qui utilise l'algorithme de Dijkstra dans un environnement à chemin négatif; il le fait en supprimant tous les bords négatifs et en rééquilibrant le graphique en premier. Cet algorithme est appelé "algorithme de Johnson".

Cela fonctionne en ajoutant un nouveau nœud (disons Q) qui a 0 coût à parcourir pour tous les autres nœuds du graphique. Il exécute ensuite Bellman-Ford sur le graphique à partir du point Q, obtenant un coût pour chaque nœud par rapport à Q, que nous appellerons q [x], qui sera soit 0, soit un nombre négatif (car il utilisait l'un des chemins négatifs). ). 

Par exemple. a -> -3 -> b, donc si on ajoute un nœud Q qui a un coût égal à 0 pour tous ces nœuds, alors q [a] = 0, q [b] = -3.

Nous rééquilibrons ensuite les arêtes à l’aide de la formule suivante: poids + q [source] - q [destination], de sorte que le nouveau poids de a-> b est égal à -3 + 0 - (-3) = 0. Nous procédons de la sorte bords dans le graphique, puis retirez Q et ses bords sortants et le tour est joué! Nous avons maintenant un graphe rééquilibré sans bord négatif sur lequel nous pouvons exécuter les dijkstra!

Le temps d'exécution est O(nm) [bellman-ford] + n x O (m log n) [n Dijkstra's] + O (n ^ 2) [calcul du poids] = O (nm log n) temps

Plus d'infos: http://joonki-jeong.blogspot.co.uk/2013/01/johnsons-algorithm.html

1

Vous pouvez utiliser les valeurs de Dijkstra sur un graphique à pondération négative, mais vous devez d'abord trouver le décalage approprié pour chaque sommet. C'est essentiellement ce que fait l'algorithme de Johnson. Mais ce serait exagéré puisque Johnson utilise Bellman-Ford pour trouver le ou les poids compensés. Johnson est conçu pour tous les chemins les plus courts entre des paires de sommets.

http://en.wikipedia.org/wiki/Johnson%27s_algorithm

1
Justin

En fait, je pense que cela fonctionnera pour modifier les poids Edge. Pas avec un offset mais avec un facteur. Supposons qu'au lieu de mesurer la distance, vous mesurez le temps requis du point A au point B.

poids = temps = distance/vitesse

Vous pouvez même adapter la vélocité en fonction de la pente pour utiliser celle physique si votre tâche est de véritables montagnes et voiture/vélo.

0
Karussell

Oui, vous pouvez le faire en ajoutant une étape à la fin, c.-à-d.

            If v ∈ Q, Then Decrease-Key(Q, v, v.d)
            Else Insert(Q, v) and S = S \ {v}.
0
sa_nyc