Given a tree of N nodes, the task is to find the maximum number of edges that can be added to the tree such that it becomes a bipartite graph.
Note: Self loop or multiple edges are not allowed but cycles are permitted.
Examples:
Input: N = 4, Edges = {{1, 2}, {2, 3}, {1, 4}}
1
/ \
2 4
/
3
Output: 1
Explanation: An edge between nodes 3 and 4 can be added such that the graph still remains bipartite.
No more than 1 edge can be added such that the resultant graph is bipartite.Input: N = 5, Edges = {{1, 2}, {1, 3}, {2, 4}, {2, 5}}
1
/ \
2 3
/ \
4 5
Output: 2
Explanation: Two edges can be added, (3, 4) and (3, 5) and the graph still remains bipartite.
Naive Approach: The basic way to solve the problem is as follows:
Assign each node of the tree as black or white such that a black node is connected with a white node (There is always such a configuration because a tree is always bipartite).
Then for all possible pair of nodes check if an edge can be added between them.
Follow the steps mentioned below to implement the above idea:
- Traverse the tree initially and assign each node as black or white such that each edge connects a black and a white node. (Trees are always bipartite).
- Iterate over all pairs of nodes, and check if an edge can be added between them.
- If both the nodes are of different colors and there is no edge between them, an edge can be added. So increment the count.
- Otherwise, no edge can be added.
- The final value of count is the answer.
Below is the implementation of the above approach.
// C++ code for the above approach: #include <bits/stdc++.h> using namespace std;
// DFS to mark nodes as black or white. void dfs( int node, int par, bool isBlack,
vector<vector< bool > >& adj,
vector< bool >& color)
{ // Mark color as black or white.
color[node] = isBlack;
for ( int i = 1; i < adj.size(); ++i) {
// If there is no edge,
// or 'i' is parent, continue.
if (!adj[node][i] || i == par)
continue ;
dfs(i, node, !isBlack, adj, color);
}
} // Function to calculate // maximum number of edges // that can be added long long maxEdges( int n,
vector<pair< int , int > > edges)
{ // Build adjacency matrix.
vector<vector< bool > > adj(n + 1,
vector< bool >(
n + 1, 0));
for ( auto i : edges) {
adj[i.first][i.second] = 1;
adj[i.second][i.first] = 1;
}
// Call DFS to color nodes.
vector< bool > color(n + 1);
dfs(1, 0, 1, adj, color);
long long ans = 0;
// Iterate over all pairs of nodes.
for ( int i = 1; i <= n; ++i) {
for ( int j = i + 1; j <= n; ++j) {
// If the color is different
// And there is no edge
// Between them, increment answer.
if (color[i] != color[j]
&& !adj[i][j])
ans++;
}
}
// Return answer.
return ans;
} // Driver Code int main()
{ int N = 4;
vector<pair< int , int > > edges
= { { 1, 2 }, { 2, 3 }, { 1, 4 } };
cout << maxEdges(N, edges);
return 0;
} |
// Java code for the above approach: import java.util.*;
public class Main {
public static void main(String[] args)
{
int N = 4 ;
List<List<Integer> > edges = new ArrayList<>();
edges.add(Arrays.asList( 1 , 2 ));
edges.add(Arrays.asList( 2 , 3 ));
edges.add(Arrays.asList( 1 , 4 ));
System.out.println(maxEdges(N, edges));
}
// Function to calculate
// maximum number of edges
// that can be added
public static long maxEdges( int n,
List<List<Integer> > edges)
{
// Build adjacency matrix.
boolean [][] adj = new boolean [n + 1 ][n + 1 ];
for ( int i = 0 ; i < edges.size(); ++i) {
adj[edges.get(i).get( 0 )][edges.get(i).get( 1 )]
= true ;
adj[edges.get(i).get( 1 )][edges.get(i).get( 0 )]
= true ;
}
// Call DFS to color nodes.
boolean [] color = new boolean [n + 1 ];
dfs( 1 , 0 , true , adj, color);
long ans = 0 ;
// Iterate over all pairs of nodes.
for ( int i = 1 ; i <= n; ++i) {
for ( int j = i + 1 ; j <= n; ++j) {
// If the color is different
// And there is no edge
// Between them, increment answer.
if (color[i] != color[j] && !adj[i][j])
ans++;
}
}
// return ans
return ans;
}
// DFS to mark nodes as black or white.
public static void dfs( int node, int par,
boolean isBlack, boolean [][] adj,
boolean [] color)
{
// Mark color as black or white.
color[node] = isBlack;
for ( int i = 1 ; i < adj.length; ++i)
{
// If there is no edge,
// or 'i' is parent, continue.
if (!adj[node][i] || i == par)
continue ;
dfs(i, node, !isBlack, adj, color);
}
}
} // This code is contributed by Tapesh(tapeshdua420) |
# Python code for the above approach: # DFS to mark nodes as black or white. def dfs(node, par, isBlack, adj, color):
# Mark color as black or white.
color[node] = isBlack
for i in range ( 1 , len (adj)):
# If there is no edge,
# or 'i' is parent, continue.
if not adj[node][i] or i = = par:
continue
dfs(i, node, not isBlack, adj, color)
# Function to calculate # maximum number of edges # that can be added def maxEdges(n, edges):
# Build adjacency matrix.
adj = [[ 0 for _ in range (n + 1 )] for _ in range (n + 1 )]
for i in edges:
adj[i[ 0 ]][i[ 1 ]] = 1
adj[i[ 1 ]][i[ 0 ]] = 1
# Call DFS to color nodes.
color = [ 0 for _ in range (n + 1 )]
dfs( 1 , 0 , 1 , adj, color)
ans = 0
# Iterate over all pairs of nodes.
for i in range ( 1 , n + 1 ):
for j in range (i + 1 , n + 1 ):
# If the color is different
# And there is no edge
# Between them, increment answer.
if color[i] ! = color[j] and not adj[i][j]:
ans + = 1
# Return answer.
return ans
# Driver Code N = 4
edges = [[ 1 , 2 ], [ 2 , 3 ], [ 1 , 4 ]]
print (maxEdges(N, edges))
# This code is contributed by tapeshdua420. |
// C# code for the above approach: using System;
using System.Collections.Generic;
using System.Linq;
class Program {
static void Main( string [] args)
{
int N = 4;
List<Tuple< int , int > > edges
= new List<Tuple< int , int > >(N);
edges.Add( new Tuple< int , int >(1, 2));
edges.Add( new Tuple< int , int >(2, 3));
edges.Add( new Tuple< int , int >(1, 4));
Console.WriteLine(maxEdges(N, edges));
}
// DFS to mark nodes as black or white.
static void dfs( int node, int par, bool isBlack,
bool [, ] adj, bool [] color)
{
// Mark color as black or white.
color[node] = isBlack;
for ( int i = 1; i < adj.GetLength(0); i++)
{
// If there is no edge,
// or 'i' is parent, continue.
if (adj[node, i] == false || i == par)
continue ;
dfs(i, node, !isBlack, adj, color);
}
}
// Function to calculate
// maximum number of edges
// that can be added
static long maxEdges( int n,
List<Tuple< int , int > > edges)
{
// Build adjacency matrix.
bool [, ] adj = new bool [n + 1, n + 1];
foreach (Tuple< int , int > tuple in edges)
{
adj[tuple.Item1, tuple.Item2] = true ;
adj[tuple.Item2, tuple.Item1] = true ;
}
// Call DFS to color nodes.
bool [] color = new bool [n + 1];
dfs(1, 0, true , adj, color);
long ans = 0;
// Iterate over all pairs of nodes.
for ( int i = 1; i <= n; ++i)
{
for ( int j = i + 1; j <= n; ++j)
{
// If the color is different
// And there is no edge
// Between them, increment answer.
if (color[i] != color[j]
&& adj[i, j] == false )
ans++;
}
}
// Return answer.
return ans;
}
} // This code is contributed by tapeshdua420. |
// JavaScript code for the above approach: // DFS to mark nodes as black or white. const dfs = (node, par, isBlack, adj, color) => { // Mark color as black or white.
color[node] = isBlack;
for (let i = 1; i < adj.length; i++) {
// If there is no edge, // or 'i' is parent, continue. if (!adj[node][i] || i === par) continue ;
dfs(i, node, !isBlack, adj, color); }
}; // Function to calculate // maximum number of edges // that can be added const maxEdges = (n, edges) => { // Build adjacency matrix.
const adj = Array.from({ length: n + 1 }, () =>
Array.from({ length: n + 1 }, () => 0) );
edges.forEach(([a, b]) => {
adj[a][b] = 1; adj[b][a] = 1; });
// Call DFS to color nodes.
const color = Array.from({ length: n + 1 }, () => false );
dfs(1, 0, true , adj, color);
let ans = 0;
// Iterate over all pairs of nodes.
for (let i = 1; i <= n; i++) {
for (let j = i + 1; j <= n; j++) {
// If the color is different
// And there is no edge
// Between them, increment answer.
if (color[i] !== color[j] && !adj[i][j]) ans++;
} }
// Return answer.
return ans;
}; // Driver Code const N = 4; const edges = [[1, 2], [2, 3], [1, 4]]; console.log(maxEdges(N, edges)); // This code is contributed by Aman Kumar. |
1
Time Complexity: O(N2)
Auxiliary Space: O(N2)
Efficient Approach: The time taken in the above approach can be optimized by using the following observation:
Say, there were initially B black nodes and W white nodes in the tree. So a bipartite graph made from these nodes can have maximum B*W edges.
Therefore, the maximum number of edges that can be added to the tree with N nodes are B*W – (N-1) [as a tree with N node has N-1 edges]
Follow the steps mentioned below:
- Traverse the tree initially and assign each node as black or white such that each edge connects a black and a white node. (Trees are always bipartite).
- Count the number of black nodes and white nodes.
- Use the formula derived above from the observation and calculate the maximum number of edges that can be added.
Below is the implementation of the above approach.
// C++ code for the above approach: #include <bits/stdc++.h> using namespace std;
// DFS to count number of black nodes. int dfs( int node, int par, bool isBlack,
vector<vector< int > >& adj)
{ int no_Of_Black = isBlack;
for ( int i : adj[node]) {
if (i == par)
continue ;
// Number of black nodes
// in each subtree.
no_Of_Black
+= dfs(i, node, !isBlack, adj);
}
return no_Of_Black;
} // Function to find maximum edges long long maxEdges( int n,
vector<pair< int , int > > edges)
{ // Build adjacency list.
vector<vector< int > > adj(n + 1);
for ( auto i : edges) {
adj[i.first].push_back(i.second);
adj[i.second].push_back(i.first);
}
// Number of black nodes.
int no_Of_Black = dfs(1, 0, 1, adj);
// Number of white nodes.
int no_Of_White = n - no_Of_Black;
// Number of edges that can be added.
return (1LL * (no_Of_Black)
* (no_Of_White)
- (n - 1));
} // Driver code int main()
{ int N = 4;
vector<pair< int , int > > edges
= { { 1, 2 }, { 2, 3 }, { 1, 4 } };
cout << maxEdges(N, edges);
return 0;
} |
// Java code for the above approach: import java.util.*;
public class Main
{ // Driver code
public static void main(String[] args)
{
int N = 4 ;
int [][] edges = { { 1 , 2 }, { 2 , 3 }, { 1 , 4 } };
System.out.println(maxEdges(N, edges));
}
// Function to find maximum edges
public static long maxEdges( int n, int [][] edges)
{
// Build adjacency list.
List<List<Integer> > adj = new ArrayList<>();
for ( int i = 0 ; i <= n; i++) {
adj.add( new ArrayList<>());
}
for ( int [] edge : edges) {
adj.get(edge[ 0 ]).add(edge[ 1 ]);
adj.get(edge[ 1 ]).add(edge[ 0 ]);
}
// Number of black nodes.
int no_Of_Black = dfs( 1 , 0 , true , adj);
// Number of white nodes.
int no_Of_White = n - no_Of_Black;
// Number of edges that can be added.
return ((no_Of_Black) * (no_Of_White) - (n - 1 ));
}
// DFS to count number of black nodes.
public static int dfs( int node, int par,
boolean isBlack,
List<List<Integer> > adj)
{
int no_Of_Black = (isBlack == true ) ? 1 : 0 ;
for ( int i : adj.get(node)) {
if (i == par)
continue ;
// Number of black nodes
// in each subtree.
no_Of_Black += dfs(i, node, !isBlack, adj);
}
return no_Of_Black;
}
} // This code is contributed by Tapesh(tapeshdua420) |
## DFS to count number of black nodes. def dfs(node, par, isBlack, adj) :
no_of_black = isBlack
for i in adj[node]:
if (i = = par):
continue
## Number of black nodes
## in each subtree.
no_of_black + = dfs(i, node, ( not isBlack), adj)
return no_of_black
def maxEdges(n, edges):
adj = []
for i in range (n + 1 ):
adj.append( list ())
## Create the graph
## From the given input.
for i in edges:
adj[i[ 0 ]].append(i[ 1 ])
adj[i[ 1 ]].append(i[ 0 ])
## Number of black nodes.
no_of_black = dfs( 1 , 0 , 1 , adj)
## Number of white nodes.
no_of_white = n - no_of_black
## Number of edges that can be added.
return (no_of_black * no_of_white) - (n - 1 )
# Driver Code if __name__ = = "__main__" :
N = 4
edges = list (( list (( 1 , 2 )), list (( 2 , 3 )), list (( 1 , 4 ))))
print (maxEdges(N, edges))
# This code is contributed by subhamgoyal2014.
|
// C# code for the above approach: using System;
using System.Collections.Generic;
class Program {
// Driver code
static void Main( string [] args)
{
int N = 4;
int [][] edges
= { new int [] { 1, 2 }, new int [] { 2, 3 },
new int [] { 1, 4 } };
Console.WriteLine(maxEdges(N, edges));
}
// Function to find maximum edges
static long maxEdges( int n, int [][] edges)
{
// Build adjacency list.
List<List< int > > adj = new List<List< int > >();
for ( int i = 0; i <= n; i++) {
adj.Add( new List< int >());
}
foreach ( int [] edge in edges)
{
adj[edge[0]].Add(edge[1]);
adj[edge[1]].Add(edge[0]);
}
// Number of black nodes.
int no_Of_Black = dfs(1, 0, true , adj);
// Number of white nodes.
int no_Of_White = n - no_Of_Black;
// Number of edges that can be added.
return ((no_Of_Black) * (no_Of_White) - (n - 1));
}
// DFS to count number of black nodes.
static int dfs( int node, int par, bool isBlack,
List<List< int > > adj)
{
int no_Of_Black = (isBlack == true ) ? 1 : 0;
foreach ( int i in adj[node])
{
if (i == par)
continue ;
// Number of black nodes
// in each subtree.
no_Of_Black += dfs(i, node, !isBlack, adj);
}
return no_Of_Black;
}
} // This code is contributed by Tapesh (tapeshdua420) |
// JavaScript code for the above approach
// DFS to count number of black nodes.
function dfs(node, par, isBlack, adj) {
let no_Of_Black = isBlack ? 1 : 0;
for (let i of adj[node]) {
if (i == par) continue ;
// Number of black nodes
// in each subtree.
no_Of_Black += dfs(i, node, !isBlack, adj);
}
return no_Of_Black;
}
// Function to find maximum edges
function maxEdges(n, edges) {
// Build adjacency list.
let adj = new Array(n + 1);
for (let i = 0; i <= n; i++) {
adj[i] = [];
}
for (let i of edges) {
adj[i[0]].push(i[1]);
adj[i[1]].push(i[0]);
}
// Number of black nodes.
let no_Of_Black = dfs(1, 0, true , adj);
// Number of white nodes.
let no_Of_White = n - no_Of_Black;
// Number of edges that can be added.
return no_Of_Black * no_Of_White - (n - 1);
}
// Driver code
let N = 4;
let edges = [[1, 2], [2, 3], [1, 4]];
console.log(maxEdges(N, edges));
// This code is contributed by Potta Lokesh |
1
Time Complexity: O(N)
Auxiliary Space: O(N)