Programación dinámica en árboles | Serie 1

La programación dinámica (DP) es una técnica para resolver problemas dividiéndolos en subproblemas superpuestos que siguen la subestructura óptima. Hay varios problemas que usan DP como suma de subconjunto, mochila, cambio de moneda, etc. DP también se puede aplicar en árboles para resolver algunos problemas específicos.
Requisito previo: DFS
Dado un árbol con N Nodes y N-1 aristas, calcule la suma máxima de los valores de los Nodes desde la raíz hasta cualquiera de las hojas sin volver a visitar ningún Node. 
 

Lo anterior es un diagrama de un árbol con N=14 Nodes y N-1=13 aristas. Los valores en el Node son 3, 2, 1, 10, 1, 3, 9, 1, 5, 3, 4, 5, 9 y 8 respectivamente para los Nodes 1, 2, 3, 4….14.  
El siguiente diagrama muestra todos los caminos desde la raíz hasta las hojas: 
 

Todas las rutas están marcadas con diferentes colores: 
Ruta 1 (rojo, 3-2-1-4): suma de todos los valores de Node = 10 
Ruta 2 (naranja, 3-2-1-5): suma de todos los valores de Node = 11 
Ruta 3 (amarillo, 3-2-3): suma de todos los valores de Node = 8 
Ruta 4 (verde, 3-1-9-9): suma de todos los valores de Node = 22 
Ruta 5 (violeta, 3-1- 9-8): suma de todos los valores de los Nodes = 21 
Ruta 6 (rosa, 3-10-1): suma de todos los valores de los Nodes = 14 
Ruta 7 (azul, 3-10-5): suma de todos los valores de los Nodes = 18 
Camino 8 (marrón, 3-10-3): suma de todos los valores de los Nodes = 16 
La respuesta es 22, ya que el Camino 4 tiene la suma máxima de valores de los Nodes en su camino desde la raíz hasta las hojas. 

El enfoque codicioso falla en este caso . Comenzando desde la raíz y tomando 3 del primer nivel, 10 del siguiente nivel y 5 del tercer nivel con avidez. El resultado es la ruta 7 si después de seguir el enfoque codicioso, por lo tanto, no aplique el enfoque codicioso aquí. 
El problema se puede resolver usando Programación Dinámica en árboles. Comience a memorizar desde las hojas y agregue el máximo de hojas a la raíz de cada subárbol. En el último paso, habrá raíz y el subárbol debajo de él, agregar el valor en el Node y el máximo del subárbol nos dará la suma máxima de los valores del Node desde la raíz hasta cualquiera de las hojas.
 

El diagrama anterior muestra cómo comenzar con las hojas y agregar el máximo de hojas de un subárbol a su raíz . Muévase hacia arriba y repita el mismo procedimiento de almacenar el máximo de hojas de cada subárbol y agregarlo a su raíz. En este ejemplo, se toma en cuenta el máximo de los Nodes 11 y 12 y luego se suma al Node 5 ( en este subárbol, 5 es la raíz y 11, 12 son sus hojas ). De manera similar, se toma en cuenta el máximo de los Nodes 13 y 14 y luego se suma al Node 7. Repita los pasos para cada subárbol hasta llegar al Node. 

Sea DP i la suma máxima de valores de Node en el camino entre i y cualquiera de sus hojas moviéndose hacia abajo. Atraviese el árbol utilizando el recorrido DFS . Almacene el máximo de todas las hojas del subárbol y agréguelo a la raíz del subárbol. Al final, el DP 1 tendrá la suma máxima de los valores de los Nodes desde la raíz hasta cualquiera de las hojas sin volver a visitar ningún Node. 
A continuación se muestra la implementación de la idea anterior: 
 

C++

// C++ code to find the maximum path sum
#include <bits/stdc++.h>
using namespace std;
 
vector<int> dp;
 
// function for dfs traversal and to store the
// maximum value in dp[] for every node till the leaves
void dfs(int a[], vector<int> v[], int u, int parent)
{
    // initially dp[u] is always a[u]
    dp[u] = a[u - 1];
 
    // stores the maximum value from nodes
    int maximum = 0;
 
    // traverse the tree
    for (int child : v[u]) {
 
        // if child is parent, then we continue
        // without recursing further
        if (child == parent)
            continue;
 
        // call dfs for further traversal
        dfs(a, v, child, u);
 
        // store the maximum of previous visited node
        // and present visited node
        maximum = max(maximum, dp[child]);
    }
 
    // add the maximum value returned to the parent node
    dp[u] += maximum;
}
 
// function that returns the maximum value
int maximumValue(int a[], vector<int> v[])
{
    dfs(a, v, 1, 0);
    return dp[1];
}
 
// Driver Code
int main()
{
    // number of nodes
    int n = 14;
 
    // adjacency list
    vector<int> v[n + 1];
 
    // create undirected edges
    // initialize the tree given in the diagram
    v[1].push_back(2), v[2].push_back(1);
    v[1].push_back(3), v[3].push_back(1);
    v[1].push_back(4), v[4].push_back(1);
    v[2].push_back(5), v[5].push_back(2);
    v[2].push_back(6), v[6].push_back(2);
    v[3].push_back(7), v[7].push_back(3);
    v[4].push_back(8), v[8].push_back(4);
    v[4].push_back(9), v[9].push_back(4);
    v[4].push_back(10), v[10].push_back(4);
    v[5].push_back(11), v[11].push_back(5);
    v[5].push_back(12), v[12].push_back(5);
    v[7].push_back(13), v[13].push_back(7);
    v[7].push_back(14), v[14].push_back(7);
 
    // values of node 1, 2, 3....14
    int a[] = { 3, 2, 1, 10, 1, 3, 9, 1, 5, 3, 4, 5, 9, 8 };
    // initialise dp
      dp = vector<int>(n+1,0);
    // function call
    cout << maximumValue(a, v);
 
    return 0;
}

Java

// Java code to find the maximum path sum
import java.util.Vector;
 
class GFG
{
    static int[] dp = new int[100];
 
    // function for dfs traversal and to
    // store the maximum value in dp[]
    // for every node till the leaves
    static void dfs(int[] a, Vector<Integer>[] v,
                    int u, int parent)
    {
 
        // initially dp[u] is always a[u]
        dp[u] = a[u - 1];
 
        // stores the maximum value from nodes
        int maximum = 0;
 
        // traverse the tree
        for (int child : v[u])
        {
 
            // if child is parent, then we continue
            // without recursing further
            if (child == parent)
                continue;
 
            // call dfs for further traversal
            dfs(a, v, child, u);
 
            // store the maximum of previous visited
            // node and present visited node
            maximum = Math.max(maximum, dp[child]);
        }
 
        // add the maximum value returned
        // to the parent node
        dp[u] += maximum;
    }
 
    // function that returns the maximum value
    static int maximumValue(int[] a,
                            Vector<Integer>[] v)
    {
        dfs(a, v, 1, 0);
        return dp[1];
    }
 
    // Driver Code
    public static void main(String[] args)
    {
 
        // Driver Code
        int n = 14;
 
        // adjacency list
        @SuppressWarnings("unchecked")
        Vector<Integer>[] v = new Vector[n + 1];
 
        for (int i = 0; i < v.length; i++)
            v[i] = new Vector<>();
 
        // create undirected edges
        // initialize the tree given in the diagram
        v[1].add(2); v[2].add(1);
        v[1].add(3); v[3].add(1);
        v[1].add(4); v[4].add(1);
        v[2].add(5); v[5].add(2);
        v[2].add(6); v[6].add(2);
        v[3].add(7); v[7].add(3);
        v[4].add(8); v[8].add(4);
        v[4].add(9); v[9].add(4);
        v[4].add(10); v[10].add(4);
        v[5].add(11); v[11].add(5);
        v[5].add(12); v[12].add(5);
        v[7].add(13); v[13].add(7);
        v[7].add(14); v[14].add(7);
 
        // values of node 1, 2, 3....14
        int a[] = { 3, 2, 1, 10, 1, 3, 9,
                    1, 5, 3, 4, 5, 9, 8 };
 
        // function call
        System.out.println(maximumValue(a, v));
    }
}
 
// This code is contributed by
// sanjeev2552

Python3

# Python3 code to find the maximum path sum
dp = [0]*100
 
# Function for dfs traversal and
# to store the maximum value in
# dp[] for every node till the leaves
def dfs(a, v, u, parent):
     
    # Initially dp[u] is always a[u]
    dp[u] = a[u - 1]
     
    # Stores the maximum value from nodes
    maximum = 0
     
    # Traverse the tree
    for child in v[u]:
         
        # If child is parent, then we continue
        # without recursing further
        if child == parent:
            continue
         
        # Call dfs for further traversal
        dfs(a, v, child, u)
         
        # Store the maximum of previous visited 
        # node and present visited node
        maximum = max(maximum, dp[child])
         
    # Add the maximum value
    # returned to the parent node
    dp[u] += maximum
 
 
# Function that returns the maximum value
def maximumValue(a, v):
    dfs(a, v, 1, 0)
    return dp[1]
 
# Driver Code
def main():
     
    # Number of nodes
    n = 14
     
    # Adjacency list as a dictionary
    v = {}
    for i in range(n + 1):
        v[i] = []
         
    # Create undirected edges
    # initialize the tree given in the diagram
    v[1].append(2), v[2].append(1)
    v[1].append(3), v[3].append(1)
    v[1].append(4), v[4].append(1)
    v[2].append(5), v[5].append(2)
    v[2].append(6), v[6].append(2)
    v[3].append(7), v[7].append(3)
    v[4].append(8), v[8].append(4)
    v[4].append(9), v[9].append(4)
    v[4].append(10), v[10].append(4)
    v[5].append(11), v[11].append(5)
    v[5].append(12), v[12].append(5)
    v[7].append(13), v[13].append(7)
    v[7].append(14), v[14].append(7)
     
    # Values of node 1, 2, 3....14
    a = [ 3, 2, 1, 10, 1, 3, 9,
          1, 5, 3, 4, 5, 9, 8 ]
     
    # Function call
    print(maximumValue(a, v))
main()
 
# This code is contributed by stutipathak31jan 

C#

// C# code to find the maximum path sum
using System;
using System.Collections.Generic;
 
class GFG
{
    static int[] dp = new int[100];
 
    // function for dfs traversal and to
    // store the maximum value in []dp
    // for every node till the leaves
    static void dfs(int[] a, List<int>[] v,
                    int u, int parent)
    {
 
        // initially dp[u] is always a[u]
        dp[u] = a[u - 1];
 
        // stores the maximum value from nodes
        int maximum = 0;
 
        // traverse the tree
        foreach(int child in v[u])
        {
 
            // if child is parent, then we continue
            // without recursing further
            if (child == parent)
                continue;
 
            // call dfs for further traversal
            dfs(a, v, child, u);
 
            // store the maximum of previous visited
            // node and present visited node
            maximum = Math.Max(maximum, dp[child]);
        }
 
        // add the maximum value returned
        // to the parent node
        dp[u] += maximum;
    }
 
    // function that returns the maximum value
    static int maximumValue(int[] a,
                            List<int>[] v)
    {
        dfs(a, v, 1, 0);
        return dp[1];
    }
 
    // Driver Code
    public static void Main(String[] args)
    {
 
        // Driver Code
        int n = 14;
 
        // adjacency list
 
        List<int>[] v = new List<int>[n + 1];
 
        for (int i = 0; i < v.Length; i++)
            v[i] = new List<int>();
 
        // create undirected edges
        // initialize the tree given in the diagram
        v[1].Add(2); v[2].Add(1);
        v[1].Add(3); v[3].Add(1);
        v[1].Add(4); v[4].Add(1);
        v[2].Add(5); v[5].Add(2);
        v[2].Add(6); v[6].Add(2);
        v[3].Add(7); v[7].Add(3);
        v[4].Add(8); v[8].Add(4);
        v[4].Add(9); v[9].Add(4);
        v[4].Add(10); v[10].Add(4);
        v[5].Add(11); v[11].Add(5);
        v[5].Add(12); v[12].Add(5);
        v[7].Add(13); v[13].Add(7);
        v[7].Add(14); v[14].Add(7);
 
        // values of node 1, 2, 3....14
        int []a = { 3, 2, 1, 10, 1, 3, 9,
                    1, 5, 3, 4, 5, 9, 8 };
 
        // function call
        Console.WriteLine(maximumValue(a, v));
    }
}
 
// This code is contributed by PrinciRaj1992

Javascript

<script>
 
// JavaScript code to find the maximum path sum
var dp = Array(100).fill(0);
 
// function for dfs traversal and to
// store the maximum value in []dp
// for every node till the leaves
function dfs(a, v, u, parent)
{
    // initially dp[u] is always a[u]
    dp[u] = a[u - 1];
    // stores the maximum value from nodes
    var maximum = 0;
    // traverse the tree
    for(var child of v[u])
    {
        // if child is parent, then we continue
        // without recursing further
        if (child == parent)
            continue;
        // call dfs for further traversal
        dfs(a, v, child, u);
        // store the maximum of previous visited
        // node and present visited node
        maximum = Math.max(maximum, dp[child]);
    }
    // add the maximum value returned
    // to the parent node
    dp[u] += maximum;
}
// function that returns the maximum value
function maximumValue(a, v)
{
    dfs(a, v, 1, 0);
    return dp[1];
}
// Driver Code
// Driver Code
var n = 14;
// adjacency list
var v = Array.from(Array(n+1), ()=>Array());
for (var i = 0; i < v.length; i++)
    v[i] = [];
// create undirected edges
// initialize the tree given in the diagram
v[1].push(2); v[2].push(1);
v[1].push(3); v[3].push(1);
v[1].push(4); v[4].push(1);
v[2].push(5); v[5].push(2);
v[2].push(6); v[6].push(2);
v[3].push(7); v[7].push(3);
v[4].push(8); v[8].push(4);
v[4].push(9); v[9].push(4);
v[4].push(10); v[10].push(4);
v[5].push(11); v[11].push(5);
v[5].push(12); v[12].push(5);
v[7].push(13); v[13].push(7);
v[7].push(14); v[14].push(7);
// values of node 1, 2, 3....14
var a = [3, 2, 1, 10, 1, 3, 9,
            1, 5, 3, 4, 5, 9, 8];
// function call
document.write(maximumValue(a, v));
 
</script>
Producción

22

Complejidad temporal: O(N), donde N es el número de Nodes.
 

Publicación traducida automáticamente

Artículo escrito por Striver y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *