Table of contents
1.
Introduction
1.1.
What is a Spanning Tree?
1.2.
Minimum Product Spanning Tree
2.
Complexity
3.
Code
3.1.
C++
3.2.
Java
3.3.
Python
3.4.
Output
4.
Frequently Asked Questions
4.1.
What are a tree and a spanning tree?
4.2.
What are the properties of a spanning tree?
4.3.
Why Prim's algorithm is greedy?
4.4.
Why is Prims better than Kruskal?
4.5.
Which is faster Prim or Kruskal?
5.
Conclusion
Last Updated: Mar 27, 2024
Medium

Minimum Product Spanning Tree

Author soham Medewar
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

Before going on to the problem, let us first understand the concept of the spanning tree. Then we will move on to the problem of minimum product spanning tree. 

minimum product spanning tree

A tree is a non-linear, hierarchical data structure made up of a number of nodes, each of which contains a value as well as a list of links to other nodes. This Data Structure is a particular way to set up data storage and organization in the computer so that it can be used more efficiently.

What is a Spanning Tree?

Suppose you are given a connected and undirected graph G where graph G has V vertices and E edges. A tree that spans all the vertices of graph G is called the spanning tree. In contrast, the spanning tree is a subgraph of graph G.

Minimum Product Spanning Tree

A spanning tree with a weight product that is less than or equal to the weight product of every other spanning tree is a minimum product spanning tree for a weighted, linked, and undirected graph. The sum of the weights assigned to each edge of the spanning tree is the weight product of the spanning tree. For the sake of simplicity, the given graph's weights will all be positive.

Problem Statement: So we need to find out the minimum product spanning tree from the given graph. The graph will be undirected. All the edges in the graph will have positive values.
 

Example: Let us look at the following example.

graph

In the above graph, we are given 5 vertices and 7 edges. The minimum product spanning tree of the above graph will be of the following edges:

0 - 1, 0 - 3, 1 - 2, 1 - 4.

The product will be 2 * 3 * 6 * 5 = 180

Approach

We can solve the above problem using minimum spanning tree algorithms (by using Prim’s or Kruskal's algorithm). Minimum spanning tree algorithms gives us the sum of minimum spanning tree. Here we need to find a minimum product spanning tree. Here we can use the property of logarithms. We know that log( a*b*c*d ) = log( a ) + log( b ) + log( c ) + log( d ).

Using the above-mentioned property, we will convert the graph into a log graph. Basically, each edge will be converted into its log value. Then, we will perform a simple Prim’s algorithm. Following is the diagram from the above approach.

Approach

Complexity

Time Complexity O(V2): The time complexity of Prim's algorithm can be decreased to O(E log V) with the use of a binary heap if the input graph is represented using an adjacency list. In this implementation, the spanning tree is always believed to begin at the graph's root.

Space Complexity: O(V)

Code

In the code below, we first created a log graph from the input graph and then passed that graph to prim's MST method, which would reduce the total sum of the tree's weights. We actually minimize the product of the weights of the spanning tree since the weights of the updated graph are logarithms of the original input graph.

C++

#include <bits/stdc++.h>
 
/* Total number of vertices in the G */
#define V 5
 
/* a utility function that searches the set of vertices not yet included in MST for the vertex with the lowest key value. */
int min_key(int key[], bool mstSet[])
{
    /* Initializing Min Value */
    int min = INT_MAX, minIndex;
 
    for (int v = 0; v < V; v++){
        if (mstSet[v] == false && key[v] < min){
            min = key[v], minIndex = v;
        }
    }
 
    return minIndex;
}
 
/* a utility method to output the Minimum Obtainable Product and the built MST saved in parent */
int print_MST(int Parent[], int n, int G[V][V])
{
    printf("Edge   Weight\n");
    int minProduct = 1;
    for (int i = 1; i < V; i++) {
        printf("%d - %d    %d \n",
               Parent[i], i, G[i][Parent[i]]);
 
        minProduct *= G[i][Parent[i]];
    }
    printf("Minimum product : %d\n",minProduct);
}
 


/* For a G represented using adjacency matrix representation input, there is a function to construct and print MST. The G is sent for edge and log printing. For actual MST operations, a G is sent. */
void prim_MST(int original_graph[V][V], double log_graph[V][V])
{
    bool mstSet[V]; /* vertices not included in MST */
    int key[V]; /* Picking up minimun */
    int parent[V]; /* Array that stores constructed MST */
 
    /* Initialize all the key with infinite value and all vertex to false */
    for (int i = 0; i < V; i++)
        key[i] = INT_MAX, mstSet[i] = false;
 
    /* Including first vertex in the MST */
    key[0] = 0; 
    parent[0] = -1; /* Assuming first node as root of MST */
 
    /* The MST will have V vertices */
    for (int count = 0; count < V - 1; count++) {
        /* Choose the minimum key vertex from the collection of vertices that aren't yet part of MST. */
        int u = min_key(key, mstSet);
 
        /* Adding the picked vertex to the MST Set */
        mstSet[u] = true;
 
        /* Update the neighbouring vertices' parent index and key value for the selected vertex. Only take into account vertices that have not yet been added to MST. */
        for (int v = 0; v < V; v++){
 
            /* Only the nearby vertices of m mst are non zero in ogGraph[u][v]. For vertices not yet included in MST, Set[v] is false. Only update the key if the log_graph[u][v] value is less than the key[v]. */
            if (log_graph[u][v] > 0 && mstSet[v] == false && log_graph[u][v] < key[v]){
                parent[v] = u, key[v] = log_graph[u][v];
            }
        }
    }
 
    /* printing the constructed MST */
    print_MST(parent, V, original_graph);
}
 
/* Method that prints minimum product spanning tree */
void minimumProductMST(int G[V][V])
{
    double log_graph[V][V];
 
    /* Constructing log_graph from original G */
    for (int i = 0; i < V; i++) {
        for (int j = 0; j < V; j++) {
            if (G[i][j] > 0)
                log_graph[i][j] = log(G[i][j]);
            else
                log_graph[i][j] = 0;
        }
    }
 
    /* Applying standard Prim's MST algorithm on Log G */
    prim_MST(G, log_graph);
}
 
/* driver program */
int main()
{
    int G[V][V] = {
        { 0, 2, 0, 6, 0 },
        { 2, 0, 3, 8, 5 },
        { 0, 3, 0, 0, 7 },
        { 6, 8, 0, 0, 9 },
        { 0, 5, 7, 9, 0 },
    };
    minimumProductMST(G);
    return 0;
}
You can also try this code with Online C++ Compiler
Run Code

Java

import java.util.*;
 
class CodingNinjas {
 
    /* Total number of vertices in the G */
    static int V = 5;
 
    /* a utility function that searches the set of vertices not yet included in MST for the vertex with the lowest key value. */
    static int min_key(int key[], boolean[] mtSet)
    {
        /* Initializing Min Value */
        int min = Integer.MAX_VALUE, minIndex = 0;
 
        for (int v = 0; v < V; v++) {
            if (mtSet[v] == false && key[v] < min) {
                min = key[v];
                minIndex = v;
            }
        }
        return minIndex;
    }
 
    /* a utility method to output the Minimum Obtainable Product and the built MST saved in Parent */
    static void print_MST(int Parent[], int n, int G[][])
    {
        System.out.printf("Edge Weight\n");
        int minProduct = 1;
        for (int i = 1; i < V; i++) {
            System.out.printf("%d - %d %d \n",
                              Parent[i], i, G[i][Parent[i]]);
 
            minProduct *= G[i][Parent[i]];
        }
        System.out.printf("Minimum product : %d\n", minProduct);
    }
 
    /* For a G represented using adjacency matrix representation input, there is a function to construct and print MST. The G is sent for edge and log printing. For actual MST operations, a G is sent. */
    static void prim_MST(int inputGraph[][], double log_graph[][])
    {
     boolean[] mtSet = new boolean[V]; /* vertices not included in MST */
     int[] key = new int[V]; /* Picking up minimun */
        int[] Parent = new int[V]; /* Array that stores constructed MST */
 
    /* Initialize all the key with infinite value and all vertex to false */
        for (int i = 0; i < V; i++) {
            key[i] = Integer.MAX_VALUE;
            mtSet[i] = false;
        }
    /* Including first vertex in the MST */
        key[0] = 0; 
        Parent[0] = -1; /* Assuming first node as root of MST */
 
     /* The MST will have V vertices */
        for (int count = 0; count < V - 1; count++) {
            /* Choose the minimum key vertex from the collection of vertices that aren't yet part of MST. */
            int u = min_key(key, mtSet);
 
            /* Adding the picked vertex to the MST Set */
            mtSet[u] = true;
 
            /* Update the neighbouring vertices' Parent index and key value for the selected vertex. Only take into account vertices that have not yet been added to MST. */
            for (int v = 0; v < V; v++) 
            {
             /* Only the nearby vertices of m mst are non zero in ogGraph[u][v]. For vertices not yet included in MST, Set[v] is false. Only update the key if the log_graph[u][v] value is less than the key[v]. */
                if (log_graph[u][v] > 0 && mtSet[v] == false && log_graph[u][v] < key[v]) {
                    Parent[v] = u;
                    key[v] = (int)log_graph[u][v];
                }
            }
        }
 
        /* printing the constructed MST */
        print_MST(Parent, V, inputGraph);
    }
 
    /* Method that prints minimum product spanning tree */
    static void minimumProductMST(int G[][])
    {
        double[][] log_graph = new double[V][V];
 
        /* Constructing log_graph from original G */
        for (int i = 0; i < V; i++) {
            for (int j = 0; j < V; j++) {
                if (G[i][j] > 0) {
                    log_graph[i][j] = Math.log(G[i][j]);
                }
                else {
                    log_graph[i][j] = 0;
                }
            }
        }
 
        /* Applying standard Prim's MST algorithm on Log G */
        prim_MST(G, log_graph);
    }
 
    /* driver program */
    public static void main(String[] args)
    {
        int G[][] = {
            { 0, 2, 0, 6, 0 },
            { 2, 0, 3, 8, 5 },
            { 0, 3, 0, 0, 7 },
            { 6, 8, 0, 0, 9 },
            { 0, 5, 7, 9, 0 },
        };
        minimumProductMST(G);
    }
}
You can also try this code with Online Java Compiler
Run Code

Python

import math

""" Total number of vertices in the G """
V = 5

""" a utility function that searches the set of vertices not yet included in MST for the vertex with the lowest key value. */* a utility function that searches the set of vertices not yet included in MST for the vertex with the lowest key value. """
def min_key(key, mstSet):

	min = 10000000
	min_index = 0
	
	for v in range(V):
	
		if (mstSet[v] == False and key[v] < min):
			min = key[v]
			min_index = v

	return min_index

""" a utility method to output the Minimum Obtainable Product and the built MST saved in Parent """
def print_MST(Parent, n, G):
	
	print("Edge Weight")
	minProduct = 1
	
	for i in range(1, V):
		print("{} - {} {} ".format(Parent[i], i, G[i][Parent[i]]))
		minProduct *= G[i][Parent[i]]
	
	print("Minimum Obtainable product is {}".format(minProduct))

"""For a G represented using adjacency matrix representation input, there is a function to construct and print MST. The G is sent for edge and log printing. For actual MST operations, a G is sent."""
def prim_MST(input_graph, log_graph):
	
	mstSet = [False for i in range(V)]

	"""Initialize all the key with infinite value and all vertex to false """
	key = [9000000 for i in range(V)]

	Parent = [0 for i in range(V)]
	
	"""Including first vertex in the MST"""
	key[0] = 0
	
	"""Assuming first node as root of MST"""
	Parent[0] = -1

	"""The MST will have V vertices"""
	for count in range(0, V - 1):
		"""Choose the minimum key vertex from the collection of vertices that aren't yet part of MST."""
		u = min_key(key, mstSet)

		"""Adding the picked vertex to the MST Set"""
		mstSet[u] = True

		"""Update the neighbouring vertices' Parent index and key value for the selected vertex. Only take into account vertices that have not yet been added to MST."""
		for v in range(V):
			"""Only the nearby vertices of m mst are non zero in ogGraph[u][v]. For vertices not yet included in MST, Set[v] is false. Only update the key if the log_graph[u][v] value is less than the key[v]."""
			if (log_graph[u][v] > 0 and mstSet[v] == False and log_graph[u][v] < key[v]):
				Parent[v] = u
				key[v] = log_graph[u][v]
	
	"""printing the constructed MST"""
	print_MST(Parent, V, input_graph)

"""Method that prints minimum product spanning tree"""
def minimumProductMST(G):

	log_graph = [[0 for j in range(V)]
				for i in range(V)]

	"""Constructing log_graph from original G"""
	for i in range(V):
		for j in range(V):
			if (G[i][j] > 0):
				log_graph[i][j] = math.log(G[i][j])
			else:
				log_graph[i][j] = 0
	
	"""Applying standard Prim's MST algorithm on Log G"""
	prim_MST(G, log_graph)

"""Driver Program"""
if __name__=='__main__':
	
	G = [ [ 0, 2, 0, 6, 0 ],
			[ 2, 0, 3, 8, 5 ],
			[ 0, 3, 0, 0, 7 ],
			[ 6, 8, 0, 0, 9 ],
			[ 0, 5, 7, 9, 0 ], ]

	minimumProductMST(G)
You can also try this code with Online Python Compiler
Run Code

Output

Edge   Weight
0 - 1    2 
1 - 2    3 
0 - 3    6 
1 - 4    5 
Minimum product : 180


Check out this problem - Largest BST In Binary Tree

Frequently Asked Questions

What are a tree and a spanning tree?

One sort of graph is a tree. A subgraph of the graph that is a tree and spans every vertex is called a spanning tree.

What are the properties of a spanning tree?

There is exactly the same number of edges and vertices in each of a graph's potential spanning trees. A cycle can never be found inside a spanning tree. If we remove one edge from the spanning tree, it will become unconnected since spanning trees are always minimally linked.

Why Prim's algorithm is greedy?

Input is rearranged by Prim's Algorithm in order to select the least expensive edge. In the sense that the algorithm strives to readjust the input to its own convenience at each iteration, we refer to Prim's Algorithm as an adaptive greedy algorithm.

Why is Prims better than Kruskal?

Prim's algorithm has an advantage over Kruskal's in that it is more complex. Prim's approach is therefore useful for handling dense networks with a large number of edges. However, when numerous edges with the same weight occur, Prim's approach doesn't provide us much control over the selected edges.

Which is faster Prim or Kruskal?

The Prim algorithm returns connected components and solely utilizes connected graphs. In dense graphs, Prim's method operates more quickly. In sparse graphs, Kruskal's algorithm operates more quickly.

Conclusion

In the above article, we have discussed the following topics Spanning Tree and Finding minimum product spanning tree.
If you want to learn more, check out our articles on Construct the Full K-ary Tree from its Preorder TraversalRegular and Bipartite graphs, and Planar and Non-Planar Graphs.

Happy Coding!

Live masterclass