Find maximum matching in a given Binary Tree
Last Updated :
28 Feb, 2023
Given a Tree with N nodes values from 1 to N and N - 1 edges. The task is to find the maximum matching in the given tree.
A matching in a tree is a collection of edges such that no pair of edges share a common node. Matching with the most edges is known as a maximum matching.
Examples:
Input: Below is the given graph:

Output: 3
Explanation:
Set of Edges in the above graph for maximum matching:
(4, 5), (1, 2), (7, 8)
Input: Below is the given graph:

Output: 3
Explanation:
Set of Edges in the above graph for maximum matching:
(4, 5), (2, 3), (1, 7)
Approach: This problem can be solved using Greedy Approach and the idea is to use post-order traversal in the tree and start with leaf edges and go up the order. Below are the steps:
- Perform DFS Traversal on the given tree with rooted node 1 and make parent as 0 and pass current nodes as a parent of the node in recursive DFS traversal.
- While performing traversal, for each node U and its parent node P if these nodes are unvisited then mark these nodes as visited and increment the maximum matching count by 1.
- Print the count of a maximum matching in the above step after DFS Traversal.
The Greedy algorithm is to repeatedly take any leaf-edge.
TreeMatch(F:forest)
M <- []
while F nonempty do {
select any leaf-edge e
M <- M + [e]
F <- F - both ends of e
}
Why the greedy algorithm works correctly?
Let's, assume E is a leaf edge and consider any maximum matching N. Suppose N does not contain E. Then if we add E to N, only one vertex now has two edges incident with it. So we can delete one of the edges of N and attain a maximum matching containing E.
Below is the implementation of the above approach:
C++
// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
#define N 10000
// Adjacency list to store edges
vector<int> 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<Integer>[] 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<Integer>();
// 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<int>[] adj = new List<int>[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<int>();
// 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
<script>
// Javascript Program to implement the above approach
let N = 10000;
// Adjacency list to store edges
let adj = new Array(N);
let used = new Array(N);
used.fill(0);
let max_matching = 0;
// Add an edge between U and V in tree
function AddEdge(u, v)
{
// Edge from u to v
adj[u].push(v);
// Edge from V to U
adj[v].push(u);
}
// Function that finds the maximum
// matching of the DFS
function Matching_dfs(u, p)
{
for(let i = 0; i < adj[u].length; 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
function maxMatching()
{
// Taking 1 as a root of the tree
Matching_dfs(1, 0);
// Print maximum Matching
document.write(max_matching + "</br>");
}
for(let i = 0; i < adj.length; i++)
adj[i] = [];
// Joining edge between
// two nodes in tree
AddEdge(1, 2);
AddEdge(1, 3);
AddEdge(3, 4);
AddEdge(3, 5);
// Function call
maxMatching();
</script>
Time Complexity: O(V + E), where V is the number of edges and E is the number of edges.
Auxiliary Space: O(V)
Bottom-up DFS approach:
Another intuitive approach to solve this problem is to use DFS in a bottom-up manner and return two values at each level
Maximum matching including the current node
Maximum matching excluding the current node
We will recurse on the left and right subtrees and get these values for both of them. We can then calculate new values for the current level based on these values.
Let left_included denote maximum matching including root of left subtree and left_excluded denote the maximum matching excluding the root of left subtree. Similarly, for right_included and right_excluded.
If we include the current node in maximum matching, then we have to exclude one of either left sub tree root or right sub tree root. Including both will cause overlapping on current node which is not allowed. By excluding either left or right sub tree root we can increase the maximum matching by 1 by including one of the edges from current_node -> left sub tree root or current_node -> right sub tree root.
Thus maximum matching including current node will be given by
current_including = max(max(left_including, right_excluding) + 1, max(left_excluding, right_including) + 1)
If we exclude the current node then we can include both left and right subtree root. As matchings in left and right subtrees are independent of each other we can get maximum value by adding both matchings.
Thus maximum matching excluding current node will be given by
current_excluding = left_including + right_including
We will return both these values from the current recursion level to upper recursion levels. After the recursion completes we will receive two values, maximum matching including root node and maximum matching excluding root node.
The maximum of those two will give the maximum matching in the tree.
C++
#include <iostream>
#include <algorithm>
using namespace std;
class Node {
public:
Node* left;
Node* right;
int val;
Node(int key) {
this->left = nullptr;
this->right = nullptr;
this->val = key;
}
};
int* maxMatchingHelper(Node* root) {
if (root == nullptr) {
int* arr = new int[2];
arr[0] = 0;
arr[1] = 0;
return arr;
}
if (root->left == nullptr && root->right == nullptr) {
int* arr = new int[2];
arr[0] = 0;
arr[1] = 0;
return arr;
}
int* left = maxMatchingHelper(root->left);
int* right = maxMatchingHelper(root->right);
// Maximum matching including current node
int currIncluded = max(max(left[0], right[1]) + 1, max(left[1], right[0]) + 1);
// Maximum matching excluding current node
int currExcluded = left[0] + right[0];
return new int[2] { currIncluded, currExcluded };
}
int maxMatching(Node* root) {
// Taking 1 as a root of the tree
int* result = maxMatchingHelper(root);
// Return maximum Matching
return max(result[0], result[1]);
}
int main() {
// Taking 1 as a root of the tree
Node* root = new Node(1);
root->left = new Node(2);
root->right = new Node(7);
root->left->left = new Node(3);
root->left->right = new Node(4);
root->left->right->left = new Node(5);
root->left->right->right = new Node(6);
root->right->left = new Node(8);
root->right->right = new Node(9);
cout << maxMatching(root) << endl;
return 0;
}
Java
class Node {
Node left, right;
int val;
public Node(int key) {
this.left = null;
this.right = null;
this.val = key;
}
}
public class Main {
public static void main(String[] args) {
// Taking 1 as a root of the tree
Node root = new Node(1);
root.left = new Node(2);
root.right = new Node(7);
root.left.left = new Node(3);
root.left.right = new Node(4);
root.left.right.left = new Node(5);
root.left.right.right = new Node(6);
root.right.left = new Node(8);
root.right.right = new Node(9);
System.out.println(maxMatching(root));
}
public static int[] maxMatchingHelper(Node root) {
if (root == null) {
return new int[]{0, 0};
}
if (root.left == null && root.right == null) {
return new int[]{0, 0};
}
int[] left = maxMatchingHelper(root.left);
int[] right = maxMatchingHelper(root.right);
// Maximum matching including current node
int currIncluded = Math.max(
Math.max(left[0], right[1]) + 1,
Math.max(left[1], right[0]) + 1
);
// Maximum matching excluding current node
int currExcluded = left[0] + right[0];
return new int[]{currIncluded, currExcluded};
}
public static int maxMatching(Node root) {
// Taking 1 as a root of the tree
int[] result = maxMatchingHelper(root);
// Return maximum Matching
return Math.max(result[0], result[1]);
}
}
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 matching 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
C#
using System;
public class Node {
public Node left;
public Node right;
public int val;
public Node(int key) {
this.left = null;
this.right = null;
this.val = key;
}
}
public class MaximumMatching {
// Helper function to compute the maximum matching for a node in the tree
private static int[] MaxMatchingHelper(Node root) {
if (root == null) {
int[] arr = new int[2];
arr[0] = 0;
arr[1] = 0;
return arr;
}
if (root.left == null && root.right == null) {
int[] arr = new int[2];
arr[0] = 0;
arr[1] = 0;
return arr;
}
int[] left = MaxMatchingHelper(root.left);
int[] right = MaxMatchingHelper(root.right);
// Maximum matching including current node
int currIncluded = Math.Max(Math.Max(left[0], right[1]) + 1, Math.Max(left[1], right[0]) + 1);
// Maximum matching excluding current node
int currExcluded = left[0] + right[0];
return new int[2] { currIncluded, currExcluded };
}
// Function to compute the maximum matching for a binary tree
public static int MaxMatching(Node root) {
// Taking 1 as the root of the tree
int[] result = MaxMatchingHelper(root);
// Return maximum matching
return Math.Max(result[0], result[1]);
}
// Main function to test the implementation
public static void Main() {
// Taking 1 as the root of the tree
Node root = new Node(1);
root.left = new Node(2);
root.right = new Node(7);
root.left.left = new Node(3);
root.left.right = new Node(4);
root.left.right.left = new Node(5);
root.left.right.right = new Node(6);
root.right.left = new Node(8);
root.right.right = new Node(9);
Console.WriteLine(MaxMatching(root)); // Output: 5
}
}
JavaScript
// JavaScript code for the above approach
class Node {
constructor(key) {
this.left = null;
this.right = null;
this.val = key;
}
}
function maxMatchingHelper(root) {
if (!root) {
return [0, 0];
}
if (!root.left && !root.right) {
return [0, 0];
}
const [leftIncluded, leftExcluded] = maxMatchingHelper(root.left);
const [rightIncluded, rightExcluded] = maxMatchingHelper(root.right);
// Maximum matching including current node
const currIncluded = Math.max(
Math.max(leftIncluded, rightExcluded) + 1,
Math.max(leftExcluded, rightIncluded) + 1
);
// Maximum matching excluding current node
const currExcluded = leftIncluded + rightIncluded;
return [currIncluded, currExcluded];
}
function maxMatching(root)
{
// Taking 1 as a root of the tree
const [rootIncluding, rootExcluding] = maxMatchingHelper(root);
// Return maximum Matching
return Math.max(rootIncluding, rootExcluding);
}
// Driver code
const root = new Node(1);
root.left = new Node(2);
root.right = new Node(7);
root.left.left = new Node(3);
root.left.right = new Node(4);
root.left.right.left = new Node(5);
root.left.right.right = new Node(6);
root.right.left = new Node(8);
root.right.right = new Node(9);
console.log(maxMatching(root));
// This code is contributed by Potta Lokesh.
Time Complexity: O(V + E), where V is the number of edges and E is the number of edges.
Auxiliary Space: O(V)
Similar Reads
Binary Search Tree in C++
A Binary Search Tree (BST) is a type of binary tree in which the data is organized and stored in a sorted order. Unlike, a binary tree that doesn't follow a specific order for node placement, in a binary search tree all the elements on the left side of a node are smaller than the node itself, and el
10 min read
Floor in Binary Search Tree (BST)
Given a Binary Search Tree and a number x, the task is to find the floor of x in the given BST, where floor means the greatest value node of the BST which is smaller than or equal to x. if x is smaller than the smallest node of BST then return -1.Examples:Input: Output: 55Explanantion: Table of Cont
14 min read
How to Read Binary Search Tree from File in C++?
A binary search tree is a hierarchical data structure in which for every node in the tree, the value of all nodes in the left subtree is less than the node's value and the value of all nodes in the right subtree is greater than the node's value. This property of the binary search tree makes it effic
4 min read
Find mirror of a given node in Binary tree
Given a Binary tree, the problem is to find the mirror of a given node. The mirror of a node is a node which exists at the mirror position of the node in opposite subtree at the root. Examples: In above tree- Node 2 and 3 are mirror nodes Node 4 and 6 are mirror nodes. Recommended PracticeMirror of
15+ min read
Find sum of all left leaves in a given Binary Tree
Given a Binary Tree, find the sum of all left leaves in it. For example, sum of all left leaves in below Binary Tree is 5+1=6. Recommended PracticeSum of Left Leaf NodesTry It! The idea is to traverse the tree, starting from root. For every node, check if its left subtree is a leaf. If it is, then a
15+ min read
Find the parent of a node in the given binary tree
Given a Binary Tree and a node, the task is to find the parent of the given node in the tree. Return -1 if the given node is the root node.Note: In a binary tree, a parent node of a given node is the node that is directly connected above the given node. Examples: Input: target = 3 Output: 1Explanati
6 min read
Find Minimum Depth of a Binary Tree
Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node. For example, minimum depth of below Binary Tree is 2. Note that the path must end on a leaf node. For example, the minimum depth of below Bi
15 min read
Find the largest Perfect Subtree in a given Binary Tree
Given a Binary Tree, the task is to find the size of largest Perfect sub-tree in the given Binary Tree. Perfect Binary Tree - A Binary tree is Perfect Binary Tree in which all internal nodes have two children and all leaves are at the same level. Examples: Input: 1 / \ 2 3 / \ / 4 5 6 Output: Size :
12 min read
Find first non matching leaves in two binary trees
Given two binary trees, find the first leaves of two trees that do not match. If there are no non-matching leaves, print nothing. Examples: Input : First Tree 5 / \ 2 7 / \ 10 11 Second Tree 6 / \ 10 15 Output : 11 15 If we consider leaves of two trees in order, we can see that 11 and 15 are the fir
14 min read
Finding Minimum Steps in Special Binary Tree
Given two integer values (i and j) as input representing two nodes of a special binary tree. The special binary tree has this property that the root node's value is always 1 and for every node, its left child will be the node's value * 3, and the right child will be ( node's value * 3) + 1. The give
8 min read