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.
Output
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
Output
1
Time Complexity: O(N)
Auxiliary Space: O(N)