Open In App

Hamiltonian Path/Cycle in Python

In graph theory, a Hamiltonian path is a path in a graph that visits each vertex exactly once, while a Hamiltonian cycle is a Hamiltonian path that forms a cycle by connecting the first and last vertices. These concepts are named after the Irish mathematician William Rowan Hamilton.

Implementing algorithms to find Hamiltonian paths and cycles is essential in various fields, including computer science, operations research, and network design. In this article, we'll dive into the theory behind Hamiltonian paths and cycles and demonstrate how to implement them in Python.

What is Hamiltonian Cycle?

Hamiltonian Cycle or Circuit in a graph G is a cycle that visits every vertex of G exactly once and returns to the starting vertex.

Understanding Hamiltonian Paths and Cycles:

A Hamiltonian path visits each vertex of a graph exactly once. If such a path exists, the graph is said to be Hamiltonian. A Hamiltonian cycle is a Hamiltonian path that forms a closed loop by connecting the starting and ending vertices.

Determining whether a Hamiltonian path or cycle exists in a given graph is an NP-complete problem, meaning it's computationally challenging to solve for large graphs. However, various algorithms and heuristics exist to find approximate solutions or efficiently solve special cases.

Algorithm:

The algorithm explores all possible paths in the graph using backtracking, ensuring each vertex is visited exactly once. If a path exists where the last vertex connects to the first vertex, a Hamiltonian cycle is found. Otherwise, the algorithm backtracks and explores alternative paths until a cycle is found or all possibilities are exhausted.

Step by step algorithm:

Below is the implementation of the above approach:

class Graph(): 
    def __init__(self, vertices): 
        self.adjacency_matrix = [[0 for column in range(vertices)]
                                    for row in range(vertices)] 
        self.vertices_count = vertices 

    def is_safe_to_add(self, v, pos, path): 
        if self.adjacency_matrix[path[pos-1]][v] == 0: 
            return False

        for vertex in path: 
            if vertex == v: 
                return False

        return True

    def hamiltonian_cycle_util(self, path, pos): 
        if pos == self.vertices_count: 
            if self.adjacency_matrix[path[pos-1]][path[0]] == 1: 
                return True
            else: 
                return False

        for v in range(1, self.vertices_count): 
            if self.is_safe_to_add(v, pos, path): 
                path[pos] = v 

                if self.hamiltonian_cycle_util(path, pos+1): 
                    return True

                path[pos] = -1

        return False

    def find_hamiltonian_cycle(self): 
        path = [-1] * self.vertices_count 

        path[0] = 0

        if not self.hamiltonian_cycle_util(path, 1): 
            print ("No\n")
            return False

        self.print_solution(path) 
        return True

    def print_solution(self, path): 
        print ("Yes\n")
        for vertex in path: 
            print (vertex )

# Example Graphs
g1 = Graph(5) 
g1.adjacency_matrix = [[0, 1, 0, 1, 0], 
                        [1, 0, 1, 1, 1], 
                        [0, 1, 0, 0, 1],
                        [1, 1, 0, 0, 1], 
                        [0, 1, 1, 1, 0]]

g1.find_hamiltonian_cycle()

Output
Yes

0
1
2
4
3

Time Complexity : O(N!), where N is number of vertices.
Auxiliary Space : O(1), since no extra space used.

Article Tags :