Open In App

Maximum product of two non-intersecting paths in a tree

Improve
Improve
Like Article
Like
Save
Share
Report

Given an undirected connected tree with N nodes (and N-1 edges), we need to find two paths in this tree such that they are non-intersecting and the product of their length is maximum. 

Examples: 

In first tree two paths which are non-intersecting
and have highest product are, 1-2 and 3-4, so answer
is 1*1 = 1
In second tree two paths which are non-intersecting 
and has highest product are, 1-3-5  and  7-8-6-2 
(or 4-8-6-2), so answer is 3*2 = 6

Maximum product of two non-intersecting paths in a tree

We can solve this problem by depth first search of tree by proceeding as follows, Since tree is connected and paths are non-intersecting, If we take any pair of such paths there must be a third path, connecting these two and If we remove an edge from the third path then tree will be divided into two components — one containing the first path, and the other containing the second path. This observation suggests us the algorithm: iterate over the edges; for each edge remove it, find the length of the path in both connected components and multiply the lengths of these paths. The length of the path in a tree can be found by modified depth first search where we will call for maximum path at each neighbor and we will add two maximum lengths returned, which will be the maximum path length at subtree rooted at current node. 

Implementation Details: 

Input is a tree, but there is no specified root in it as we have only collection of edges. The tree is represented as undirected graph. We traverse adjacency list. For every edge, we find maximum length paths on both sides of it (after removing the edge). We keep track of maximum product caused by an edge removal.  

C++




// C++ program to find maximum product of two
// non-intersecting paths
#include <bits/stdc++.h>
using namespace std;
 
/*  Returns maximum length path in subtree rooted
    at u after removing edge connecting u and v */
int dfs(vector<int> g[], int& curMax, int u, int v)
{
    // To find lengths of first and second maximum
    // in subtrees. currMax is to store overall
    // maximum.
    int max1 = 0, max2 = 0, total = 0;
 
    //  loop through all neighbors of u
    for (int i = 0; i < g[u].size(); i++)
    {
        //  if neighbor is v, then skip it
        if (g[u][i] == v)
            continue;
 
        //  call recursively with current neighbor as root
        total = max(total, dfs(g, curMax, g[u][i], u));
 
        //  get max from one side and update
        if (curMax > max1)
        {
            max2 = max1;
            max1 = curMax;
        }
        else
            max2 = max(max2, curMax);
    }
 
    // store total length by adding max
    // and second max
    total = max(total, max1 + max2);
 
    // update current max by adding 1, i.e.
    // current node is included
    curMax = max1 + 1;
    return total;
}
 
// method returns maximum product of length of
// two non-intersecting paths
int maxProductOfTwoPaths(vector<int> g[], int N)
{
    int res = INT_MIN;
    int path1, path2;
 
    // one by one removing all edges and calling
    // dfs on both subtrees
    for (int i = 1; i < N+2; i++)
    {
        for (int j = 0; j < g[i].size(); j++)
        {
            // calling dfs on subtree rooted at
            // g[i][j], excluding edge from g[i][j]
            // to i.
            int curMax = 0;
            path1 = dfs(g, curMax, g[i][j], i);
 
            //  calling dfs on subtree rooted at
            // i, edge from i to g[i][j]
            curMax = 0;
            path2 = dfs(g, curMax, i, g[i][j]);
 
            res = max(res, path1 * path2);
        }
    }
    return res;
}
 
// Utility function to add an undirected edge (u,v)
void addEdge(vector<int> g[], int u, int v)
{
    g[u].push_back(v);
    g[v].push_back(u);
}
 
//  Driver code to test above methods
int main()
{
    int edges[][2] = {{1, 8}, {2, 6}, {3, 1},
                      {5, 3}, {7, 8}, {8, 4},
                      {8, 6} };
    int N = sizeof(edges)/sizeof(edges[0]);
 
    // there are N edges, so +1 for nodes and +1
    // for 1-based indexing
    vector<int> g[N + 2];
    for (int i = 0; i < N; i++)
         addEdge(g, edges[i][0], edges[i][1]);
 
    cout << maxProductOfTwoPaths(g, N) << endl;
    return 0;
}


Java




// Java program to find maximum product
// of two non-intersecting paths
import java.util.*;
 
class GFG{
static int curMax;
 
// Returns maximum length path in
// subtree rooted at u after
// removing edge connecting u and v
static int dfs(Vector<Integer> g[], 
               int u, int v)
{
     
    // To find lengths of first and
    // second maximum in subtrees.
    // currMax is to store overall
    // maximum.
    int max1 = 0, max2 = 0, total = 0;
 
    // Loop through all neighbors of u
    for(int i = 0; i < g[u].size(); i++)
    {
         
        // If neighbor is v, then skip it
        if (g[u].get(i) == v)
            continue;
 
        // Call recursively with current
        // neighbor as root
        total = Math.max(total, dfs(
            g, g[u].get(i), u));
 
        // Get max from one side and update
        if (curMax > max1)
        {
            max2 = max1;
            max1 = curMax;
        }
        else
            max2 = Math.max(max2, curMax);
    }
 
    // Store total length by adding max
    // and second max
    total = Math.max(total, max1 + max2);
 
    // Update current max by adding 1, i.e.
    // current node is included
    curMax = max1 + 1;
    return total;
}
 
// Method returns maximum product of
// length of two non-intersecting paths
static int maxProductOfTwoPaths(Vector<Integer> g[],
                                int N)
{
    int res = Integer.MIN_VALUE;
    int path1, path2;
 
    // One by one removing all edges and
    // calling dfs on both subtrees
    for(int i = 1; i < N + 2; i++)
    {
        for(int j = 0; j < g[i].size(); j++)
        {
             
            // Calling dfs on subtree rooted at
            // g[i][j], excluding edge from g[i][j]
            // to i.
            curMax = 0;
            path1 = dfs(g, g[i].get(j), i);
 
            // Calling dfs on subtree rooted at
            // i, edge from i to g[i][j]
            curMax = 0;
            path2 = dfs(g,i, g[i].get(j));
 
            res = Math.max(res, path1 * path2);
        }
    }
    return res;
}
 
// Utility function to add an
// undirected edge (u,v)
static void addEdge(Vector<Integer> g[],
                    int u, int v)
{
    g[u].add(v);
    g[v].add(u);
}
 
//  Driver code
public static void main(String[] args)
{
    int edges[][] = { { 1, 8 }, { 2, 6 },
                      { 3, 1 }, { 5, 3 },
                      { 7, 8 }, { 8, 4 },
                      { 8, 6 } };
                       
    int N = edges.length;
 
    // There are N edges, so +1 for nodes
    // and +1 for 1-based indexing
    @SuppressWarnings("unchecked")
    Vector<Integer> []g = new Vector[N + 2];
    for(int i = 0; i < g.length; i++)
        g[i] = new Vector<Integer>();
         
    for(int i = 0; i < N; i++)
         addEdge(g, edges[i][0], edges[i][1]);
 
    System.out.print(maxProductOfTwoPaths(g, N) + "\n");
}
}
 
// This code is contributed by Princi Singh


Python3




# Python3 program to find maximum product of two
# non-intersecting paths
 
# Returns maximum length path in subtree rooted
# at u after removing edge connecting u and v
def dfs(g, curMax, u, v):
     
    # To find lengths of first and second maximum
    # in subtrees. currMax is to store overall
    # maximum.
    max1 = 0
    max2 = 0
    total = 0
 
    # loop through all neighbors of u
    for i in range(len(g[u])):
         
        # if neighbor is v, then skip it
        if (g[u][i] == v):
            continue
 
        # call recursively with current neighbor as root
        total = max(total, dfs(g, curMax, g[u][i], u))
 
        # get max from one side and update
        if (curMax[0] > max1):
            max2 = max1
            max1 = curMax[0]
        else:
            max2 = max(max2, curMax[0])
 
    # store total length by adding max
    # and second max
    total = max(total, max1 + max2)
 
    # update current max by adding 1, i.e.
    # current node is included
    curMax[0] = max1 + 1
    return total
 
# method returns maximum product of length of
# two non-intersecting paths
def maxProductOfTwoPaths(g, N):
    res = -999999999999
    path1, path2 = None, None
 
    # one by one removing all edges and calling
    # dfs on both subtrees
    for i in range(N):
        for j in range(len(g[i])):
             
            # calling dfs on subtree rooted at
            # g[i][j], excluding edge from g[i][j]
            # to i.
            curMax = [0]
            path1 = dfs(g, curMax, g[i][j], i)
 
            # calling dfs on subtree rooted at
            # i, edge from i to g[i][j]
            curMax = [0]
            path2 = dfs(g, curMax, i, g[i][j])
 
            res = max(res, path1 * path2)
    return res
 
# Utility function to add an undirected edge (u,v)
def addEdge(g, u, v):
    g[u].append(v)
    g[v].append(u)
 
# Driver code 
if __name__ == '__main__':
    edges = [[1, 8], [2, 6], [3, 1], [5, 3], [7, 8], [8, 4], [8, 6]]
    N = len(edges)
 
    # there are N edges, so +1 for nodes and +1
    # for 1-based indexing
    g = [[] for i in range(N + 2)]
    for i in range(N):
        addEdge(g, edges[i][0], edges[i][1])
    print(maxProductOfTwoPaths(g, N))
     
# This code is contributed by PranchalK   


C#




// C# program to find maximum product
// of two non-intersecting paths
using System;
using System.Collections.Generic;
 
public class GFG
{
  static int curMax;
 
  // Returns maximum length path in
  // subtree rooted at u after
  // removing edge connecting u and v
  static int dfs(List<int> []g, 
                 int u, int v)
  {
 
    // To find lengths of first and
    // second maximum in subtrees.
    // currMax is to store overall
    // maximum.
    int max1 = 0, max2 = 0, total = 0;
 
    // Loop through all neighbors of u
    for(int i = 0; i < g[u].Count; i++)
    {
 
      // If neighbor is v, then skip it
      if (g[u][i] == v)
        continue;
 
      // Call recursively with current
      // neighbor as root
      total = Math.Max(total, dfs(
        g, g[u][i], u));
 
      // Get max from one side and update
      if (curMax > max1)
      {
        max2 = max1;
        max1 = curMax;
      }
      else
        max2 = Math.Max(max2, curMax);
    }
 
    // Store total length by adding max
    // and second max
    total = Math.Max(total, max1 + max2);
 
    // Update current max by adding 1, i.e.
    // current node is included
    curMax = max1 + 1;
    return total;
  }
 
  // Method returns maximum product of
  // length of two non-intersecting paths
  static int maxProductOfTwoPaths(List<int> []g,
                                  int N)
  {
    int res = int.MinValue;
    int path1, path2;
 
    // One by one removing all edges and
    // calling dfs on both subtrees
    for(int i = 1; i < N + 2; i++)
    {
      for(int j = 0; j < g[i].Count; j++)
      {
 
        // Calling dfs on subtree rooted at
        // g[i,j], excluding edge from g[i,j]
        // to i.
        curMax = 0;
        path1 = dfs(g, g[i][j], i);
 
        // Calling dfs on subtree rooted at
        // i, edge from i to g[i,j]
        curMax = 0;
        path2 = dfs(g,i, g[i][j]);
 
        res = Math.Max(res, path1 * path2);
      }
    }
    return res;
  }
 
  // Utility function to add an
  // undirected edge (u,v)
  static void addEdge(List<int> []g,
                      int u, int v)
  {
    g[u].Add(v);
    g[v].Add(u);
  }
 
  //  Driver code
  public static void Main(String[] args)
  {
    int [,]edges = { { 1, 8 }, { 2, 6 },
                    { 3, 1 }, { 5, 3 },
                    { 7, 8 }, { 8, 4 },
                    { 8, 6 } };
 
    int N = edges.GetLength(0);
 
    // There are N edges, so +1 for nodes
    // and +1 for 1-based indexing
    List<int> []g = new List<int>[N + 2];
    for(int i = 0; i < g.Length; i++)
      g[i] = new List<int>();
 
    for(int i = 0; i < N; i++)
      addEdge(g, edges[i,0], edges[i,1]);
 
    Console.Write(maxProductOfTwoPaths(g, N) + "\n");
  }
}
 
// This code is contributed by aashish1995


Javascript




<script>
    // Javascript program to find maximum product of two
    // non-intersecting paths
    let curMax;
  
    // Returns maximum length path in
    // subtree rooted at u after
    // removing edge connecting u and v
    function dfs(g, u, v)
    {
 
      // To find lengths of first and
      // second maximum in subtrees.
      // currMax is to store overall
      // maximum.
      let max1 = 0, max2 = 0, total = 0;
 
      // Loop through all neighbors of u
      for(let i = 0; i < g[u].length; i++)
      {
 
        // If neighbor is v, then skip it
        if (g[u][i] == v)
          continue;
 
        // Call recursively with current
        // neighbor as root
        total = Math.max(total, dfs(
          g, g[u][i], u));
 
        // Get max from one side and update
        if (curMax > max1)
        {
          max2 = max1;
          max1 = curMax;
        }
        else
          max2 = Math.max(max2, curMax);
      }
 
      // Store total length by adding max
      // and second max
      total = Math.max(total, max1 + max2);
 
      // Update current max by adding 1, i.e.
      // current node is included
      curMax = max1 + 1;
      return total;
    }
 
    // Method returns maximum product of
    // length of two non-intersecting paths
    function maxProductOfTwoPaths(g, N)
    {
      let res = Number.MIN_VALUE;
      let path1, path2;
 
      // One by one removing all edges and
      // calling dfs on both subtrees
      for(let i = 1; i < N + 2; i++)
      {
        for(let j = 0; j < g[i].length; j++)
        {
 
          // Calling dfs on subtree rooted at
          // g[i,j], excluding edge from g[i,j]
          // to i.
          curMax = 0;
          path1 = dfs(g, g[i][j], i);
 
          // Calling dfs on subtree rooted at
          // i, edge from i to g[i,j]
          curMax = 0;
          path2 = dfs(g,i, g[i][j]);
 
          res = Math.max(res, path1 * path2);
        }
      }
      return res;
    }
 
    // Utility function to add an
    // undirected edge (u,v)
    function addEdge(g, u, v)
    {
      g[u].push(v);
      g[v].push(u);
    }
     
    let edges = [ [ 1, 8 ], [ 2, 6 ],
                    [ 3, 1 ], [ 5, 3 ],
                    [ 7, 8 ], [ 8, 4 ],
                    [ 8, 6 ] ];
  
    let N = edges.length;
  
    // There are N edges, so +1 for nodes
    // and +1 for 1-based indexing
    let g = [];
    for(let i = 0; i < N + 2; i++)
    {
        g.push([]);
    }
    for(let i = 0; i < g.length; i++)
      g[i] = [];
  
    for(let i = 0; i < N; i++)
      addEdge(g, edges[i][0], edges[i][1]);
  
    document.write(maxProductOfTwoPaths(g, N) + "</br>");
 
// This code is contributed by divyesh072019.
</script>


Output

6

 



Last Updated : 08 Jul, 2022
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads