1
votes

Nombre de chemins distincts dans l'arborescence, qui ont une valeur de nœuds dans ce chemin supérieure ou égale à K

Énoncé du problème:
Vous recevez un entier N indiquant le nombre de nœuds dans cet arbre. Maintenant, vous devez compter le nombre de chemins distincts dans l'arborescence, de sorte que la valeur minimale du nœud dans ce chemin soit supérieure ou égale à k .

Format d'entrée: p >

  1. La première ligne contient le nombre total de nœuds N dans cet arbre et un valeur entière positive K .
  2. Les lignes N-1 suivantes contiennent une paire d'entiers u, v (les valeurs ne sont pas séparées par des virgules), qui indiquent qu'il y a une arête entre le nœud u et v , dans l'arborescence.

Exemple:

1 <= N <= 10^5
1 <= u,v <= N  
1 <= K <= 10^6  

Résultat attendu:

3

Edit: Je n'arrive pas à penser à comment aborder ce problème. Alors, veuillez me donner un indice, afin que je puisse essayer de l'implémenter davantage. Je serai reconnaissant à la moindre aide.

Mise à jour:

4 2  
1 2  
2 3  
3 4  

Une approche naïve d'un tel problème ne passera dans aucune circonstance. La complexité de la solution doit être O (n ** 2) ou O (nlogn).


11 commentaires

@ גלעדברקן Je veux juste un indice pour déterminer un moyen, pour obtenir tous les chemins possibles du nœud racine au nœud enfant, qui satisfont la contrainte donnée avec le moins de complexité. S'il existe un algorithme pour le même, alors je peux facilement déterminer le nombre total de sous-chemins en utilisant nC2 , où n est le nombre total de nœuds dans ce chemin distinct .


Où dans la question est-il dit "nœud racine vers nœud enfant?" Il dit simplement, "chemins distincts ... dans l'arbre ..."


Oui tu as raison. Mais dans un arbre, vous avez une relation hiérarchique entre les nœuds. J'ai donc utilisé le terme nœud racine vers nœud enfant .


Considérons un arbre ayant 20 nœuds. L'un des chemins du nœud de départ au nœud final a 5 nœuds au total, et tous satisfont à la contrainte donnée. Par conséquent, on peut facilement dire que le nombre total de chemins distincts dans cette route sera 5C2 .


Veuillez utiliser un terme autre que «racine» pour décrire le point de départ d'un chemin. C'est trop déroutant :) (Je n'ai pas compris votre commentaire précédent.) (Et aux modérateurs - veuillez arrêter de déplacer les commentaires pour discuter lorsque les commentaires sont pertinents pour la question proprement dite!)


continuons cette discussion dans le chat .


Veuillez clarifier si ce problème concerne un arbre ou un graphique général.


@ גלעדברקן Il s'agit de l'arbre car, s'il s'agissait d'un graphe, supposons que si nous voulons déterminer les chemins distincts de ce nœud x au reste des nœuds et, si le nœud x < / code> faisait partie du cycle, alors la longueur du chemin serait infinie si elle avait satisfait toutes les contraintes. Par conséquent, c'est définitivement un arbre. En aucun cas, ce ne sera un graphique.


Techniquement, tous les graphiques ne contiennent pas de cycles. Mais même avec un graphe acyclique dirigé, je pense que ma réponse devrait fonctionner.


@ גלעדברקן, La structure de données impliquée dans ce problème n'est pas un graphe (ni cyclique ni acyclique). Et en ce qui concerne votre solution, la structure de données que vous avez utilisée est vraiment complexe et le code n'est pas du tout lisible en raison de l'utilisation de noms de variables non pertinents comme f et a, b & c .


Non seulement les variables que j'ai utilisées sont pertinentes, mais la réponse fonctionne avec une complexité O (n). N'hésitez pas à demander si quelque chose vous semble déroutant.


3 Réponses :


1
votes

Résolvons ce problème dans un cas plus simple, supposons que tous les nœuds de l'arborescence sont supérieurs à k , donc le nombre de chemins valides est nC2 .

Et, nous faisons également une observation qu'un chemin valide ne peut contenir aucun nœud inférieur à k , nous devrons donc supprimer tous les nœuds inférieurs à k code > de l'arborescence, qui créera le sous-arbre n - k , ainsi le résultat final sera

result = somme de nC2 de tous les sous-arbres p>

Algorithme simple:

remove all edges that connect to nodes that less than k

for each node that >= k and not marked as visited
  do bfs to count number of node in that subtree
  result += nC2

return result


11 commentaires

Je suppose que c'est la solution la plus appropriée à ce jour. J'attends d'autres avis d'experts sur cette approche, car je ne suis pas en mesure de décider si c'est la meilleure approche ou une approche un peu meilleure qui existe encore.


"Supposons que tous les nœuds de l'arbre sont supérieurs à k, donc le nombre de chemins valides est nC2" - qu'en est-il de l'entrée k = 1, 1 -> 2, 2 -> 3, 1 -> 4, 4 -> 5 5 choisissez 2 = 10, mais nous n'avons que 3 + 3 chemins valides distincts. Ai-je mal compris votre réponse? (J'ai ajouté une réponse récursive, au fait.)


@ גלעדברקן Hmm, je pense qu'il y a 10 chemins: 1 -> 2, 1 -> 3, 1 -> 4, 1 -> 5, 2-> 3, 2-> 4, 2-> 5, 3 -> 4, 3-> 5, 4-> 5 . Est-ce que je manque quelque chose?


Oui, vous manquez quelque chose. Dans l'exemple de mon commentaire ci-dessus, 5 ou 4 ne sont pas accessibles depuis 2.


@ גלעדברקן dans ce cas, il vous manque l'exigence qu'il s'agisse d'un arbre :), s'il s'agit d'un graphe orienté, alors vous avez peut-être raison? Mais je pense que ce n'est pas dirigé, car il n'y a pas de concept d'arbre dirigé, et l'énoncé du problème est un bord entre les nœuds u et v , pas un bord de u à v , la direction n'est pas implicite ici.


Dans mon exemple, 2 et 4 sont les enfants de 1. Ceci est un arbre. Pourquoi le sous-arbre droit serait-il accessible depuis la gauche, comme vous semblez le suggérer? Peut-être ai-je eu tort de supposer que les chemins ne peuvent pas aller d'un sous-arbre à l'autre?


Voici une citation du premier commentaire des OP sous la question: "..veux ​​un indice pour déterminer un moyen, pour obtenir tous les chemins possibles du nœud racine au nœud enfant." (OP signifie racine pour tout sous-arbre.)


La question n'est pas de savoir s'il existe des arbres dirigés mais si les chemins sont supposés dirigés de haut en bas. L'OP (et moi) semblions le penser, mais peut-être que l'OP se trompe.


Le mot «entre» n'implique pas de direction, comme vous l'avez indiqué, mais le choix de l'ordre de n'importe quelle paire de nœuds dans l'entrée pourrait impliquer une direction.


@ גלעדברקן Hmm, vous avez un point, si c'est le cas, et si c'est un arbre valide, donc je pense que l'algo devra modifier un peu :)


De cette façon, c'est bon. Toutes les possibilités sont couvertes entre les réponses :)



1
votes

Ce problème peut être résolu en utilisant la programmation dynamique sur les arbres, vous pouvez en savoir plus ici https://www.geeksforgeeks.org/dynamic-programming-trees-set-2/ .

Séparons le problème en deux parties, la première est de trouver le nombre de chemins qui sont valides dans le sous-arbre d'un nœud u . La deuxième partie est de trouver la réponse pour le nœud u si nous ne considérons pas son sous-arbre mais en allant à son parent et ainsi de suite.

Considérons 1 comme la racine de l'arborescence.

Maintenant pour résoudre la première partie, nous allons créer un tableau dans [] dans lequel nous allons stocker le le nombre de chemins dans le sous-arbre du nœud u donc dans [u] représentera le nombre de chemins valides à partir du nœud u et en visitant son sous-arbre. Pour calculer ce tableau, nous pouvons exécuter un simple dfs comme suit:

// u is the current node - p is the parent
void dfs2(int u, int p) {
    for (int i = 0; i < g[u].size(); i++) { // iterate through the adjacency of node u
        int v = g[u][i]; // v is the child of u
        if (v != p) { // in case v is the parent just ignore it
            if (v >= k && u >= k) { // if value of u or v is less than k then we cant start at this node so it should be 0
                out[v] += (out[u] + 1); //add to the number of paths of v the number of paths from it's parent (u) + 1 if we dont use the subtree of u
                out[v] += (in[u] - in[v] - 1); // add to the number of paths of v the number of paths from it's parent (u)
                // we should subtract in[v] + 1 because we want to exclude this branch from the subtree of the parent
            }
            dfs2(v, u); // go to node v
        }
    }
}

Pour résoudre la deuxième partie, nous avons besoin d'un tableau out [] avec out [u] étant le nombre de chemins valides si l'on ne considère pas le sous-arbre de u qui va au parent de u et ainsi sur.

permet d'appeler le parent de u P [u] . Pour calculer out [u] nous nous baserons sur p [u] . out [i] est le nombre de chemins valides si nous allons à p [u] , et ce que nous pouvons faire une fois que nous atteignons p [u] code > est soit passer par son sous-arbre (à l'exclusion de la brach de u bien sûr) ou visiter p [p [u]] (le parent du parent de u ) donc out [u] est (out [p [u]] + 1) + (in [p [u]] - in [u] - 1) code>.

//u is the current node - p is the parent
void dfs1(int u, int p) {
    for (int i = 0; i < g[u].size(); i++) { //iterate through the adjacency of node u
        int v = g[u][i]; // v is the child of u
        if (v != p) { //in case v is the parent just ignore it
            dfs1(v, u); //go to node v
            if (u >= k && v >= k) { //if value of u or v is less than k then we cant start at this node so it should be 0
                in[u] += in[v] + 1; //add to number of paths of u the number of paths starting from the node v + 1 (+1 because we can also go from u to v)
            }
        }
    }
}

Pour trouver la réponse, additionnez simplement tout out [u] + in [u] pour tous les nœuds et divisez par 2 car chaque chemin a été calculé deux fois.

complexité O (V + E)


0 commentaires

1
votes

Pour les arbres, en supposant que les chemins que nous énumérons sont dirigés de haut en bas, nous pouvons le formuler récursivement. Soit f (T, k) un tuple, [a, b] , où a est le nombre de chemins valides distincts dans T qui commencent à T ; et b , le nombre de chemins valides distincts dans T qui commencent à un nœud inférieur. Tous les nœuds dans des chemins valides ont une valeur supérieure ou égale à k .

Alors (code Python):

T = {
  "value": 1,
  "children": [
    {
      "value": 2,
      "children": [
        {
          "value": 3,
          "children": [
            {
              "value": 4,
              "children": []
            }
          ]
        }
      ]
    }
  ]
}

print f(T, 2)  # [0, 3]

La réponse serait alors be a + b , après avoir appelé f depuis la racine de l'arborescence.

Sortie:

def f(T, k):
  if not T["children"]:
    return [0, 0]

  result = [0, 0]

  for c in T["children"]:
    [a, b] = f(c, k)
    result[1] += a + b

    if T["value"] >= k <= c["value"]:
      # One valid path from T to c
      # plus extending all the paths
      # that start at c
      result[0] += 1 + a

  return result

p>


0 commentaires