Il existe cet algorithme standard pour rechercher le plus long chemin dans les arbres non dirigés à l'aide de deux recherches en profondeur:
- Démarrez DFS à partir d'un sommet aléatoire et recherchez le sommet le plus éloigné. disons qu'il est .v ′
- Maintenant, démarrez un DFS à partir de pour trouver le sommet le plus éloigné. Ce chemin est le plus long chemin du graphique.
La question est de savoir si cela peut être fait plus efficacement. Peut-on le faire avec un seul DFS ou BFS?
(Cela peut être décrit de manière équivalente comme le problème du calcul du diamètre d'un arbre non dirigé.)
algorithms
graphs
trees
emmy
la source
la source
Réponses:
Nous effectuons une recherche en profondeur d'abord en ordre postérieur et nous agrégons les résultats en route, c'est-à-dire que nous résolvons le problème de manière récursive.
Pour chaque nœud avec les enfants (dans l’arborescence de recherche), il existe deux cas:u 1 , … , u kv u1,…,uk
Dans le second cas, nous devons combiner le ou les plus longs chemins de dans l'un des sous-arbres; ce sont certainement ceux qui ont les feuilles les plus profondes. La longueur du chemin est alors si , ou si , avec le jeu multiple de hauteurs de sous-arbres¹.H ( k ) + H ( k - 1 ) + 2 k > 1 H ( k ) + 1 k = 1 H = { h ( T u i ) | i = 1 , ... , k }v H(k)+H(k−1)+2 k>1 H(k)+1 k=1 H={h(Tui)∣i=1,…,k}
En pseudo-code, l'algorithme ressemble à ceci:
la source
height1 + height2
est la longueur de ce chemin. S'il s'agit bien du plus long chemin, il est choisi parmax
. C'est aussi expliqué dans le texte ci-dessus, donc je ne vois pas trop votre problème? Vous devez sûrement récidiver afin de déterminer s’il s’agit bien du chemin le plus long, et même si ce n’est pas le cas, cela ne fait pas mal (à juste titre) de récidiver.height2
explicitement touteheight1
considération, comment peut-il choisir le même enfant deux fois? Cela a également été expliqué dans le texte d'introduction.longestPathHeight(T)
renvoie une paire(h,d)
, oùh
est la hauteurT
etd
le diamètre deT
. (Droite?)Cela peut être résolu d'une meilleure façon. De plus, nous pouvons réduire la complexité temporelle à O (n) en modifiant légèrement la structure des données et en utilisant une approche itérative. Pour une analyse détaillée et de multiples façons de résoudre ce problème avec diverses structures de données.
Voici un résumé de ce que je veux expliquer dans un de mes articles de blog :
Approche récursive - Diamètre de l'arbre Une autre façon d'aborder ce problème est la suivante. Comme nous l'avons mentionné ci-dessus, le diamètre peut
Ce qui signifie que le diamètre peut être dérivé idéalement de
Et nous savons que le diamètre est le chemin le plus long, nous prenons donc le maximum de 1 et 2 au cas où il se trouverait dans le côté ou bien 3 si il couvre la racine.
Approche itérative - Diamètre de l'arbre
Nous avons un arbre, nous avons besoin d'une méta-information avec chacun des nœuds pour que chaque nœud sache ce qui suit:
Une fois que chaque nœud a cette information, nous avons besoin d’une variable temporaire pour suivre le chemin maximum. Au moment où l'algorithme se termine, nous avons la valeur de diamètre dans la variable temp.
Maintenant, nous devons résoudre ce problème dans une approche ascendante, car nous n'avons aucune idée des trois valeurs de la racine. Mais nous connaissons ces valeurs pour les feuilles.
Étapes à résoudre
À un noeud donné,
la source
Le code ci-dessous renvoie un chemin de diamètre utilisant un seul parcours DFS. Cela nécessite un espace supplémentaire pour garder trace du meilleur diamètre vu jusqu'à présent, ainsi que du chemin le plus long commençant à un nœud particulier de l'arbre. Il s'agit d'une approche de programmation dynamique basée sur le fait qu'un chemin de plus grand diamètre n'inclut pas la racine, ou est une combinaison des deux plus longs chemins des voisins de la racine. Nous avons donc besoin de deux vecteurs pour garder une trace de cette information.
la source