📌  相关文章
📜  在给定的二叉树中找到最大匹配

📅  最后修改于: 2021-10-26 05:43:23             🧑  作者: Mango

给定具有N 个节点值从1 到 NN – 1 条边的树。任务是在给定的树中找到最大匹配。

例子:

方法:这个问题可以使用 Greedy Approach 来解决,其思想是在树中使用后序遍历,从叶子边缘开始,向上移动。以下是步骤:

  1. 在具有根节点 1 的给定树上执行 DFS 遍历并使父节点为 0,并在递归 DFS 遍历中将当前节点作为节点的父节点传递。
  2. 在执行遍历时,对于每个节点U及其父节点P,如果这些节点未被访问,则将这些节点标记为已访问并将最大匹配计数增加 1。
  3. 在 DFS 遍历之后打印上述步骤中最大匹配的计数。

Greedy 算法是重复取任何叶子边缘。

TreeMatch(F:forest)
M <- []
while F nonempty do {
     select any leaf-edge e
     M <- M + [e]
     F <- F - both ends of e
  }

为什么贪心算法能正常工作?
让我们假设E是叶子边缘并考虑任何最大匹配N 。假设N不包含E 。然后,如果我们将E添加到N ,则现在只有一个顶点有两条边与之相关。所以我们可以删除N 的一条边并获得包含E的最大匹配。

下面是上述方法的实现:

C++
// C++ program for the above approach
#include 
using namespace std;
#define N 10000
 
// Adjacency list to store edges
vector adj[N];
 
int used[N];
int max_matching;
 
// Add an edge between U and V in tree
void AddEdge(int u, int v)
{
    // Edge from u to v
    adj[u].push_back(v);
 
    // Edge from V to U
    adj[v].push_back(u);
}
 
// Function that finds the maximum
// matching of the DFS
void Matching_dfs(int u, int p)
{
    for (int i = 0;
         i < adj[u].size(); i++) {
 
        // Go further as we are not
        // allowed to go towards
        // its parent
        if (adj[u][i] != p) {
            Matching_dfs(adj[u][i], u);
        }
    }
 
    // If U and its parent P is
    // not taken then we must
    // take &mark them as taken
    if (!used[u] and !used[p] and p != 0) {
 
        // Increment size of edge set
        max_matching++;
        used[u] = used[p] = 1;
    }
}
 
// Function to find the maximum
// matching in a graph
void maxMatching()
{
    // Taking 1 as a root of the tree
    Matching_dfs(1, 0);
 
    // Print maximum Matching
    cout << max_matching << "\n";
}
 
// Driver Code
int main()
{
    int n = 5;
 
    // Joining edge between
    // two nodes in tree
    AddEdge(1, 2);
    AddEdge(1, 3);
    AddEdge(3, 4);
    AddEdge(3, 5);
 
    // Function Call
    maxMatching();
    return 0;
}


Java
// Java program for the above approach
import java.util.*;
 
class GFG{
     
static final int N = 10000;
 
// Adjacency list to store edges
@SuppressWarnings("unchecked")
static Vector[] adj = new Vector[N];
 
static int used[] = new int[N];
static int max_matching;
 
// Add an edge between U and V in tree
static void AddEdge(int u, int v)
{
     
    // Edge from u to v
    adj[u].add(v);
 
    // Edge from V to U
    adj[v].add(u);
}
 
// Function that finds the maximum
// matching of the DFS
static void Matching_dfs(int u, int p)
{
    for(int i = 0; i < adj[u].size(); i++)
    {
         
        // Go further as we are not
        // allowed to go towards
        // its parent
        if (adj[u].get(i) != p)
        {
            Matching_dfs(adj[u].get(i), u);
        }
    }
 
    // If U and its parent P is
    // not taken then we must
    // take &mark them as taken
    if (used[u] == 0 &&
        used[p] == 0 && p != 0)
    {
         
        // Increment size of edge set
        max_matching++;
        used[u] = used[p] = 1;
    }
}
 
// Function to find the maximum
// matching in a graph
static void maxMatching()
{
     
    // Taking 1 as a root of the tree
    Matching_dfs(1, 0);
 
    // Print maximum Matching
    System.out.print(max_matching + "\n");
}
 
// Driver Code
public static void main(String[] args)
{
    for(int i = 0; i < adj.length; i++)
        adj[i] = new Vector();
         
    // Joining edge between
    // two nodes in tree
    AddEdge(1, 2);
    AddEdge(1, 3);
    AddEdge(3, 4);
    AddEdge(3, 5);
 
    // Function call
    maxMatching();
}
}
 
// This code is contributed by amal kumar choubey


Python3
# Python3 program for the above approach
N = 10000
 
# Adjacency list to store edges
adj = {}
 
used = [0 for i in range(N)]
 
max_matching = 0
 
# Add an edge between U and V in tree
def AddEdge(u, v):
     
    if u not in adj:
        adj[u] = []
    if v not in adj:
        adj[v] = []
 
    # Edge from u to v
    adj[u].append(v)
 
    # Edge from V to U
    adj[v].append(u)
 
# Function that finds the maximum
# matching of the DFS
def Matching_dfs(u, p):
     
    global max_matching
     
    for i in range(len(adj[u])):
 
        # Go further as we are not
        # allowed to go towards
        # its parent
        if (adj[u][i] != p):
            Matching_dfs(adj[u][i], u)
 
    # If U and its parent P is
    # not taken then we must
    # take &mark them as taken
    if (not used[u] and not used[p] and p != 0):
         
        # Increment size of edge set
        max_matching += 1
        used[u] = 1
        used[p] = 1
 
# Function to find the maximum
# matching in a graph
def maxMatching():
 
    # Taking 1 as a root of the tree
    Matching_dfs(1, 0)
 
    # Print maximum Matching
    print(max_matching)
     
# Driver Code
n = 5
 
# Joining edge between
# two nodes in tree
AddEdge(1, 2)
AddEdge(1, 3)
AddEdge(3, 4)
AddEdge(3, 5)
 
# Function Call
maxMatching()
 
# This code is contributed by avanitrachhadiya2155


C#
// C# program for the above approach
using System;
using System.Collections.Generic;
 
class GFG{
     
static readonly int N = 10000;
 
// Adjacency list to store edges
static List[] adj = new List[N];
 
static int []used = new int[N];
static int max_matching;
 
// Add an edge between U and V in tree
static void AddEdge(int u, int v)
{
     
    // Edge from u to v
    adj[u].Add(v);
 
    // Edge from V to U
    adj[v].Add(u);
}
 
// Function that finds the maximum
// matching of the DFS
static void Matching_dfs(int u, int p)
{
    for(int i = 0; i < adj[u].Count; i++)
    {
         
        // Go further as we are not
        // allowed to go towards
        // its parent
        if (adj[u][i] != p)
        {
            Matching_dfs(adj[u][i], u);
        }
    }
 
    // If U and its parent P is
    // not taken then we must
    // take &mark them as taken
    if (used[u] == 0 &&
        used[p] == 0 && p != 0)
    {
         
        // Increment size of edge set
        max_matching++;
        used[u] = used[p] = 1;
    }
}
 
// Function to find the maximum
// matching in a graph
static void maxMatching()
{
     
    // Taking 1 as a root of the tree
    Matching_dfs(1, 0);
 
    // Print maximum Matching
    Console.Write(max_matching + "\n");
}
 
// Driver Code
public static void Main(String[] args)
{
    for(int i = 0; i < adj.Length; i++)
        adj[i] = new List();
         
    // Joining edge between
    // two nodes in tree
    AddEdge(1, 2);
    AddEdge(1, 3);
    AddEdge(3, 4);
    AddEdge(3, 5);
 
    // Function call
    maxMatching();
}
}
 
// This code is contributed by amal kumar choubey


Javascript


Python3
class Node:
    def __init__(self, key):
        self.left = None
        self.right = None
        self.val = key
         
def max_matching_helper(root):
  if not root:
    return (0, 0)
   
  if not root.left and not root.right:
    return (0, 0)
   
  left_included, left_excluded = max_matching_helper(root.left)
  right_included, right_excluded = max_matching_helper(root.right)
   
  # Maximum matchin gincluding current node
  curr_included = max(max(left_included, right_excluded) + 1, max(left_excluded, right_included) + 1)
  # Maximum matching excluding current node
  curr_excluded = left_included + right_included
   
  return (curr_included, curr_excluded)
   
         
def max_matching(root):
  # Taking 1 as a root of the tree
  root_including, root_excluding = max_matching_helper(root)
   
  # Return maximum Matching
  return max(root_including, root_excluding)
 
# Driver code
root = Node(1)
root.left = Node(2)
root.right = Node(7)
root.left.left = Node(3)
root.left.right = Node(4)
root.left.right.left = Node(5)
root.left.right.right = Node(6)
root.right.left = Node(8)
root.right.right = Node(9)
 
print(max_matching(root))
 
# This code is contributed by Rathijeet Bhave


输出
2

时间复杂度: O(V + E),其中 V 是边数,E 是边数。
辅助空间: O(V)

自下而上的 DFS 方法

解决这个问题的另一种直观方法是自底向上使用DFS,每层返回两个值

包括当前节点的最大匹配

排除当前节点的最大匹配

我们将在左子树和右子树上递归并为它们获取这些值。然后我们可以根据这些值计算当前级别的新值。

设 left_included 表示包含左子树根的最大匹配,left_excluded 表示不包含左子树根的最大匹配。同样,对于 right_included 和 right_excluded。

如果我们将当前节点包含在最大匹配中,那么我们必须排除左子树根或右子树根之一。包含两者将导致当前节点重叠,这是不允许的。通过排除左子树根或右子树根,我们可以通过包含来自 current_node -> 左子树根或 current_node -> 右子树根的边之一,将最大匹配增加 1。

因此,包括当前节点的最大匹配将由下式给出

如果我们排除当前节点,那么我们可以同时包含左子树根和右子树根。由于左右子树中的匹配是相互独立的,我们可以通过添加两个匹配来获得最大值。

因此,排除当前节点的最大匹配将由下式给出

我们将从当前递归级别返回这两个值到上递归级别。递归完成后,我们将收到两个值,包括根节点的最大匹配和不包括根节点的最大匹配。

这两者中的最大值将给出树中的最大匹配。

蟒蛇3

class Node:
    def __init__(self, key):
        self.left = None
        self.right = None
        self.val = key
         
def max_matching_helper(root):
  if not root:
    return (0, 0)
   
  if not root.left and not root.right:
    return (0, 0)
   
  left_included, left_excluded = max_matching_helper(root.left)
  right_included, right_excluded = max_matching_helper(root.right)
   
  # Maximum matchin gincluding current node
  curr_included = max(max(left_included, right_excluded) + 1, max(left_excluded, right_included) + 1)
  # Maximum matching excluding current node
  curr_excluded = left_included + right_included
   
  return (curr_included, curr_excluded)
   
         
def max_matching(root):
  # Taking 1 as a root of the tree
  root_including, root_excluding = max_matching_helper(root)
   
  # Return maximum Matching
  return max(root_including, root_excluding)
 
# Driver code
root = Node(1)
root.left = Node(2)
root.right = Node(7)
root.left.left = Node(3)
root.left.right = Node(4)
root.left.right.left = Node(5)
root.left.right.right = Node(6)
root.right.left = Node(8)
root.right.right = Node(9)
 
print(max_matching(root))
 
# This code is contributed by Rathijeet Bhave
输出
3

时间复杂度:O(V + E),其中 V 是边数,E 是边数。

辅助空间:O(V)

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程