Open In App

XOR Graph Minimum Spanning Tree

Last Updated : 12 Jan, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given a complete weighted graph where edges have weights determined by the bitwise-xor operation. The graph has N vertices numbered from 0 to N-1, and each undirected edge between vertices u and v has a weight of u XOR v. The task is to determine the minimum total weight of the spanning tree.

Examples:

Input: n = 4
Output: 4
Explanation: The three edges of MST will be between

  • Node 0 and 1 with cost = 1
  • Node 2 and 3 with cost = 1
  • Node 1 and 3 with cost = 2

Total cost = 1 + 1 + 2 = 4

Input: n = 6
Output: 9
Explanation: The five edges of MST will be between

  • Node 0 and 1 with cost = 1
  • Node 2 and 3 with cost = 1
  • Node 4 and 5 with cost = 1
  • Node 1 and 3 with cost = 2
  • Node 1 and 5 with cost = 4

Total cost = 1 + 1 + 1 + 2 + 4 = 9

Approach: The problem can be solved using the following approach:

The intuition is based on the properties of the XOR operation and the structure of a complete graph. Here’s the key idea:

  1. In a complete graph, each pair of vertices is connected by an edge. The problem states that the weight of an edge between vertices u and v is u XOR v. The XOR operation has a special property: for any two numbers u and v, u XOR v is minimum when u and v differ only in the least significant bit. This means that the edges with the smallest weights are those where the vertices differ only in the least significant bit.
  2. The problem asks for the minimum total weight of the spanning tree. A spanning tree of a graph is a tree that includes all the vertices of the graph. The minimum spanning tree is the spanning tree where the sum of the weights of the edges is as small as possible. One way to find the minimum spanning tree is to use Kruskal’s algorithm, which is a greedy algorithm that adds the smallest edge that doesn’t form a cycle until all vertices are included.
  3. Our implementation would also be a similar greedy approach. It starts by considering the edges with the smallest weights, which are those where the vertices differ only in the least significant bit. For each bit position, it calculates how many edges have that bit position as the least significant bit and adds their weights to the total weight of the spanning tree. It does this by maintaining a count of the remaining vertices and a running total of the edge weights and halving the count of vertices in each step.

This approach works because in each step, it’s choosing the smallest edge that doesn’t form a cycle, which is the key idea in Kruskal’s algorithm. And it’s able to do this efficiently without looking at every edge, thanks to the properties of the XOR operation and the structure of the complete graph.

Steps to solve the problem:

  • Initialize k to 1, which will be used to calculate the weight of the edges in the graph.
  • Initialize ans to 0, which will hold the total weight of the minimum spanning tree.
  • Run a while loop if n > 1. In each iteration, do the following:
    • It adds k*(n/2) to ans. This is because in each step, we’re choosing n/2 edges with weight k to add to the spanning tree. The weight k is chosen based on the property of the XOR operation: for any two numbers u and v, u XOR v is minimum when u and v differ only in the least significant bit. So, you’re choosing the edges in increasing order of their weights, which is the key idea in Kruskal’s algorithm for finding the minimum spanning tree.
    • It multiplies k by 2. This is because in the next step, we’ll be choosing edges with the next higher weight.
    • It subtracts n/2 from n. This is because we’ve already considered n/2 vertices in the current step, so we subtract them from n.
  • Finally, prints ans, which is the total weight of the minimum spanning tree.

Below is the implemantation of the above approach:

C++




#include <iostream>
using namespace std;
 
long long n, k, ans; // Declare variables n, k, and ans
 
int main()
{
    // Read the number of vertices from the input
    n = 4;
    // Initialize k to 1. k represents the current
    // weight being considered.
    k = 1;
 
    // While there are more than one vertices left
    while (n > 1) {
        // Add the total weight of edges with weight k to
        // ans. The number of such edges is n/2.
        ans += k * (n / 2);
 
        // Double the weight for the next iteration
        k <<= 1LL;
 
        // Half the number of vertices for the next
        // iteration
        n = (n + 1) / 2;
    }
 
    // Print the total weight of the minimum spanning tree
    cout << ans;
}


Java




import java.util.Scanner;
 
public class Main {
    public static void main(String[] args)
    {
        // Read the number of vertices from the input
        long n = 4;
        // Initialize k to 1. k represents the current
        // weight being considered.
        long k = 1;
 
        long ans = 0; // Declare variable ans
 
        // While there are more than one vertices left
        while (n > 1) {
            // Add the total weight of edges with weight k
            // to ans. The number of such edges is n/2.
            ans += k * (n / 2);
 
            // Double the weight for the next iteration
            k <<= 1;
 
            // Half the number of vertices for the next
            // iteration
            n = (n + 1) / 2;
        }
 
        // Print the total weight of the minimum spanning
        // tree
        System.out.println(ans);
    }
}


Python3




# Python Implementation
 
n = 4
k = 1
ans = 0
 
while n > 1:
    ans += k * (n // 2)
    k <<= 1
    n = (n + 1) // 2
 
print(ans)
 
 
# This code is contributed by Tapesh(tapeshdua420)


C#




using System;
 
namespace MinimumSpanningTree
{
    class Program
    {
        static void Main(string[] args)
        {
            long n, k, ans = 0; // Declare variables n, k, and ans and initialize ans to 0
 
            // Read the number of vertices from the input
            n = 4;
            // Initialize k to 1. k represents the current
            // weight being considered.
            k = 1;
 
            // While there are more than one vertices left
            while (n > 1)
            {
                // Add the total weight of edges with weight k to
                // ans. The number of such edges is n/2.
                ans += k * (n / 2);
 
                // Double the weight for the next iteration
                k <<= 1;
 
                // Half the number of vertices for the next
                // iteration
                n = (n + 1) / 2;
            }
 
            // Print the total weight of the minimum spanning tree
            Console.WriteLine(ans);
        }
    }
}
 
 
// This code is contributed by akshitaguprzj3


Javascript




// JS Implementation
 
let n = 4;
let k = 1;
let ans = 0;
 
while (n > 1) {
    ans += k * Math.floor(n / 2);
    k <<= 1;  // Bitwise left shift
    n = Math.floor((n + 1) / 2);
}
 
console.log(ans);
 
 
// This code is conitrbuted by Tapesh(tapeshdua420)


Output

4







Time Complexity: O(log(N)), where N is the total number of vertices in the graph.
Auxiliary Space: O(1)



    Like Article
    Suggest improvement
    Share your thoughts in the comments

    Similar Reads