📜  树中两条不相交路径的最大乘积

📅  最后修改于: 2022-05-13 01:57:54.346000             🧑  作者: Mango

树中两条不相交路径的最大乘积

给定一棵有 N 个节点(和 N-1 条边)的无向连通树,我们需要在这棵树中找到两条不相交的路径,并且它们的长度的乘积最大。

例子:

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

树中两条不相交路径的最大乘积

我们可以通过树的深度优先搜索来解决这个问题,方法如下,由于树是连接的并且路径不相交,如果我们采用任何一对这样的路径,则必须有第三条路径连接这两个路径,如果我们删除一个来自第三条路径的边,然后树将分为两个部分——一个包含第一个路径,另一个包含第二个路径。这一观察为我们提供了算法:迭代边缘;对于每条边删除它,在两个连接的组件中找到路径的长度并将这些路径的长度相乘。树中路径的长度可以通过修改后的深度优先搜索找到,我们将在每个邻居处调用最大路径,我们将添加两个返回的最大长度,这将是在当前节点为根的子树的最大路径长度。

实施细节:
输入是一棵树,但其中没有指定的根,因为我们只有边的集合。树表示为无向图。我们遍历邻接表。对于每条边,我们在它的两侧找到最大长度的路径(移除边之后)。我们跟踪由边缘去除引起的最大产品。

C++
// C++ program to find maximum product of two
// non-intersecting paths
#include 
using namespace std;
  
/*  Returns maximum length path in subtree rooted
    at u after removing edge connecting u and v */
int dfs(vector 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 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 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 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 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 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 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 []g = new Vector[N + 2];
    for(int i = 0; i < g.length; i++)
        g[i] = new Vector();
          
    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 []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 []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 []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 []g = new List[N + 2];
    for(int i = 0; i < g.Length; i++)
      g[i] = new List();
  
    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


输出:

6