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:
Parmi les points ci-dessus, j'ai les pensées suivantes:
count
pour le nombre de chemins les plus courtsglobal level
global level
d'un à chaque fois, puis BFS atteint un nouveau niveaushortest level
pour le chemin le plus court vers wglobal level
au shortest level
et au count++
; global level
est égal au shortest level
, j'augmente count
à chaque fois que j'ai rencontré w à nouveau.global level
devient plus grand que le shortest level
, je termine le voyage, car je cherche le chemin le plus court, pas le chemin.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?
Voici quelques idées à ce sujet.
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.
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.
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.
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:
d[j] = -1
, définissez d[j] := level
et z[j] := z[i]
.d[j] = level
, définissez z[j] := z[j] + z[i]
.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
.
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.
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.
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.
Puis-je le faire de cette façon
À 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?
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.