web-dev-qa-db-fra.com

Comment trouver le nombre de chemins les plus courts différents entre deux sommets, en graphe orienté et en temps linéaire?

Voici l'exercice:

Soit v et w deux sommets dans un graphe orienté G = (V, E). Concevez un algorithme de temps linéaire pour trouver le nombre de chemins les plus courts différents (pas nécessairement les sommets des sommets) entre v et w. Note: les arêtes en G ne sont pas pondérées


Pour cette accise, je résume comme suit:

  1. C'est un graphe orienté
  2. Il demande le nombre de différents chemins les plus courts. Premièrement, les chemins doivent être les plus courts, puis il peut y avoir plus d’un chemin aussi court dont la longueur est la même.
  3. entre v et w, il faut donc compter à la fois de v à w et de w à v.
  4. temps linéaire. 
  5. Le graphique n'est pas pondéré.

Parmi les points ci-dessus, j'ai les pensées suivantes:

  1. Je n’ai pas besoin d’utiliser Algorithme de Dijkstra car le graphique n’est pas pondéré et nous essayons de trouver tous les chemins les plus courts, pas seulement un seul.
  2. Je maintiens une count pour le nombre de chemins les plus courts
  3. Je voudrais d'abord utiliser BFS à partir de v et conserver également une information global level
  4. J'augmente le global level d'un à chaque fois, puis BFS atteint un nouveau niveau
  5. Je gère également les informations shortest level pour le chemin le plus court vers w
  6. La première fois que je rencontre w en voyage, j'attribue le global level au shortest level et au count++
  7. tant que le global level est égal au shortest level, j'augmente count à chaque fois que j'ai rencontré w à nouveau.
  8. si le global level devient plus grand que le shortest level, je termine le voyage, car je cherche le chemin le plus court, pas le chemin.
  9. Puis je fais 2 - 8 encore pour w to v

Mon algorithme est-il correct? Si je fais v à w puis w à v, est-ce que cela est toujours considéré comme temps linéaire?

24
Jackson Tale

Voici quelques idées à ce sujet.

  • Il ne peut exister que les chemins les plus courts allant de v-> w au nœud x, soit s'il existe plusieurs chemins menant à x passant par le même sommet, soit si x est rencontré plusieurs fois au même niveau DFS.

Preuve: S'il y a plusieurs chemins entrant dans x par le même sommet, il y a évidemment plusieurs façons de passer par x. C'est simple. Supposons maintenant qu’il n’ya qu’un seul chemin dans x pour chaque sommet allant dans x (au maximum). 

Si x a déjà été rencontré, aucun des chemins actuels ne peut contribuer à un autre chemin le plus court. Comme x a déjà été rencontré, tous les chemins pouvant suivre seront au moins un plus longs que le chemin le plus court précédent. Par conséquent, aucun de ces chemins ne peut contribuer à la somme. 

Cela signifie cependant que nous rencontrons chaque nœud au plus une fois et que nous en avons terminé. Donc, un BFS normal est très bien.

  • Nous n'avons même pas besoin de connaître le niveau, mais nous pouvons obtenir le nombre final une fois que nous avons rencontré le nœud final.

Cela peut être compilé dans un algorithme très simple, qui est principalement juste BFS.

 - Mark nodes as visited as usual with BFS.
 - Instead of adding just nodes to the queue in the DFS add nodes plus number of incoming paths.
 - If a node that has been visited should be added ignore it.
 - If you find a node again, which is currently in the queue, do not add it again, instead add the counts together.
 - Propagate the counts on the queue when adding new nodes.
 - when you encounter the final, the number that is stored with it, is the number of possible paths.
19
LiKao

Votre algorithme casse sur un graphique comme

  *   *   *   1
 / \ / \ / \ / \
v   *   *   *   w
 \ / \ / \ / \ /
  *   *   *   2

avec tous les bords dirigés de gauche à droite. Il compte deux chemins, l'un à travers 1 et l'autre à 2, mais 1 et 2 peuvent être atteints à partir de v par huit chemins les plus courts différents, pour un total de seize.

9
qrqrq

Comme le montre qrqrq, votre algorithme échoue sur certains graphiques, mais l'idée de BFS est bonne. Au lieu de cela, conservez un tableau z de taille |V| que vous initialisez à zéro; conservez le nombre de chemins les plus courts menant à un sommet découvert i à une distance inférieure à level dans z[i]. Conservez également un tableau d de taille |V| tel que d[i] soit la distance entre v et le sommet i si cette distance est inférieure à level. Initialisez level à 0, d[v] à 0 et z[v] à 1 (il existe un seul chemin de longueur 0 allant de v à v) et définissez toutes les autres entrées de d à -1 et de z à 0.

Maintenant, chaque fois que vous rencontrez un bord de i à j dans votre BFS, alors:

  • Si d[j] = -1, définissez d[j] := level et z[j] := z[i].
  • Si d[j] = level, définissez z[j] := z[j] + z[i].
  • Sinon, ne faites rien.

La raison en est que pour chaque chemin le plus court allant de v à i, il existe un chemin le plus court allant de v à j. Cela donnera le nombre de chemins les plus courts de v à chaque sommet en temps linéaire. Répétez l'opération maintenant, mais à partir de w.

4
Erik P.

Cet algorithme me semble correct.

Comme vous le savez, BFS est une recherche temporelle linéaire (O(N)) car le temps T requis pour la compléter est, au pire, T = C + a * N, où N est le nombre de nœuds et C, a sont des constantes fixes.

Dans votre cas, effectuer la recherche deux fois - d'abord de v à w, puis de w à v - est (au pire) 2T ou 2C + 2a * N, ce qui satisfait également l'exigence de temps linéaire O(N) si vous définissez un nouveau C' = 2C et un nouveau a' = 2a, car C' et a' sont également des constantes fixes.

2
Dan Nissenbaum
int edgeCb( graphPT g, int x, int y )
{
    if ( dist[ y ] > dist[ x ] + 1 ) {
        dist[ y ] = dist[ x ] + 1; // New way
        ways[ y ] = ways[ x ]; // As many ways as it's parent can be reached
    } else if ( dist[ y ] == dist[ x ] + 1 ) {
        ways[ y ] += ways[ x ]; // Another way
    } else {
        // We already found a way and that is the best
        assert( dist[ y ] < g->nv );
    }
    return 1;
}

Le code ci-dessus me donne des résultats corrects pour tous les types de graphiques mentionnés dans ce post. Fondamentalement, il s'agit d'un rappel Edge pour la traversée BFS.

dist [début] = 0; façons [début] = 1;

pour le repos tous les sommets dist [x] = numberOfVertices; // C'est au-delà du maximum de désaccord possible

BFS (g, début);

Si way [fin] n'est pas nul, cela représente le nombre de voies et dist [end] représente la distance la plus courte.

Incase façons [fin] == 0 signifie que la fin ne peut pas être atteinte du début.

S'il vous plaît laissez-moi savoir s'il y a des trous de boucle dans ce domaine.

2
vamsi

Solution la plus simple en changeant BFS:

compte (v) = 0, compte (s) = 1. pour chaque voisin u de v, si (d (v) + 1 == d (u)), compte (u) + = compte (v). maintenant tout réinitialiser et faire la même chose à partir du sommet.

2
Ilan Aizelman WS

Puis-je le faire de cette façon 

  1. Je traverse avec BFS jusqu'à ce que j'atteigne le sommet de la destination et que je maintienne les niveaux
  2. Une fois que j'atteins le niveau de destination, j'utilise la table de niveau comme suit

À partir de la table de niveau, je commence à revenir en arrière en comptant le nombre de parents jusqu'au sommet de notre chemin (la première fois, ce serait le sommet de destination). 
À chaque étape, je multiplie le nombre de parents distincts trouvés à ce niveau-là par les chemins les plus courts que je puisse avoir jusqu'au sommet de destination.
Je monte dans les niveaux, en ne considérant que les nœuds qui se trouvent sur mon chemin et en multipliant le nombre de parents distincts trouvés à chaque niveau jusqu'à ce que j'atteigne le niveau 0.

Est-ce que ça marche?

0
Rahul Krishna

Il suffit de vérifier la bonne explication donnée ici:

https://www.geeksforgeeks.org/number-shortest-paths-unweighted-directed-graph/

En bref, nous pouvons modifier n’importe quel algorithme de chemin le plus court, Et lorsque l’étape de mise à jour arrive, le compteur du nombre de Chemins le plus court précédemment découverts augmente lorsque la proposition de chemin en cours a la même longueur que le chemin le plus court jusqu'à ce moment-là.

Dans le cas particulier, lorsqu'il s'agit d'un graphique non pondéré ou ayant une pondération Constante pour toutes les arêtes, le moyen le plus simple consiste à modifier un BFS.

0
jonaprieto