Count all Hamiltonian paths in a given directed graph


Introduction

In graph theory, a Hamiltonian path is a sequence of vertices that visits each vertex exactly once, with no repeated edges. It is named after Sir William Rowan Hamilton, an Irish mathematician who contributed significantly to various fields, including graph theory. In this article, we will dive deep into understanding and counting all possible Hamiltonian paths within a directed graph using C++ programming. Now, it's up to us to apply these principles and unlock the secrets concealed within different types of directed graphs.

Count all Hamiltonian paths in a given directed graph

A directed graph consists of a set of vertices connected by edges that have specific orientations or directions. Unlike undirected graphs where edges are bidirectional or going either way, directed graphs impose strict directionality upon their edges.

Input

In the above code, we have taken the input as the adjacent matrix,

0 1 0 1 0
1 0 1 1 0
0 1 0 1 1
1 1 1 0 1
0 0 1 1 0

When the algorithm reaches a vertex that has not been visited before, it marks that vertex as visited and recursively explores all possible paths from that vertex. If the algorithm has visited all vertices exactly once, it increments the hamilton_paths_count variable by 1.

Example

The algorithm starts at vertex 0 and recursively explores all possible paths from that vertex. The algorithm keeps track of which vertices have been visited so far using the visited_nodes array.

The six Hamiltonian path that can be constructed is,

0 -> 1 -> 2 -> 3 -> 4
0 -> 3 -> 2 -> 1 -> 4
0 -> 3 -> 4 -> 1 -> 2
0 -> 1 -> 4 -> 3 -> 2
0 -> 2 -> 1 -> 4 -> 3
0 -> 2 -> 3 -> 4 -> 1

Therefore, the count is 6 in the given directed graph.

Approach 1: C++ code to count all Hamiltonian paths in a given directed graph using the recursive function

Counting all the possible Hamiltonian paths in a given directed graph requires an extensive search strategy known as backtracking. The approach systematically explores every feasible solution and discards any possibilities found to be unviable along the way.

Algorithm

  • Step 1 − Begin by defining the data structures necessary for processing.

  • Step 2 − Create an adjacency matrix (2D array) to represent our directed graph.

  • Step 3 − Define variables such as number_of_vertices to store the total count and hamilton_paths_count initialized as 0.

  • Step 4 − Keep track of visited nodes using another array called visited_nodes, initially marking all vertices as not visited.

  • Step 5 − Given the vertices, we must look for edges between them and steer clear of any vertices that have previously been visited by the function.

  • Step 6 − Develop functions required for computational purposes.

    • createGraph() − Initialize the adjacency matrix representing vertex connections based on user-defined input or random generation methods.

    • hamiltonPath() − Recursive function exploring each possibility while taking care not to visit already traversed vertices more than once.

  • Step 7 − The output is printed.

Example

//The header file to include the input and output is used
// Maximum number of vertices
#include<iostream>
#define V 5 

// Declaring variable for counting Hamiltonian paths
//Adjacent matrix is initialized 
int hamilton_paths_count = 0; 
int graph[V][V] = {
   {0, 1, 0, 1, 0},
   {1, 0, 1, 1, 0},
   {0, 1, 0, 1, 1},
   {1, 1, 1, 0, 1},
   {0, 0, 1, 1, 0}
}; 
// Adjacency matrix representing the directed graph
bool visited_nodes[V];
//Implementation to obtain user-defined or random initialization of adjacency matrix
void createGraph() {
    
}

void hamiltonPath(int current_vertex, int total_vertices_visited) {
   // Base case: all vertices have been visited once
   // Increment count for a valid Hamiltonian path found
   if(total_vertices_visited == V) { 
      hamilton_paths_count++; 
      return;
   }
   // Here, before invoking this function recursively, we make sure that an edge exists between two connected vertices and that the following vertices have not already been visited*/    
   visited_nodes[current_vertex] = true; 
   for(int i=0;i<V;i++) {
      if(graph[current_vertex][i]!=0 && !visited_nodes[i]) {   
         hamiltonPath(i, total_vertices_visited+1);     
         //We increment the total_vertices_visited by 1 and move on to check if there are more valid paths from this point. Rinse and repeat!
         //Once a recursive iteration is complete, reset 'visited' status while backtracking **/
         visited_nodes[i] = false;              
      }
   }    
}
//main function to test the code
int main() {
   createGraph(); 

   memset(visited_nodes,false,sizeof(visited_nodes)); // Initialize all nodes as unvisited
   hamiltonPath(0,1);

   std::cout << "Total Hamiltonian Paths: " <<hamilton_paths_count<<std::endl;

   return 0;
}

Output

Total Hamiltonian Paths: 6

Conclusion

The most common programming languages are C and C++, by using any one of these languages, we can easily deal with the Hamiltonian paths. This path comes under the mathematical operations, by using the graph theory we can find the total path from the input of the adjacent matrix. The approach used in the above code is the recursive function.

Updated on: 25-Aug-2023

162 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements