Open In App

Hamiltonian Cycle

Last Updated : 25 May, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

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.

  • If a graph contains a Hamiltonian cycle, it is called Hamiltonian graph otherwise it is non-Hamiltonian.
  • Finding a Hamiltonian Cycle in a graph is a well-known NP-complete problem, which means that there's no known efficient algorithm to solve it for all types of graphs. However, it can be solved for small or specific types of graphs.
  • The Hamiltonian Cycle problem has practical applications in various fields, such as logistics, network design, and computer science.

What is Hamiltonian Path?

Hamiltonian Path in a graph G is a path that visits every vertex of G exactly once and it doesn't have to return to the starting vertex. It's an open path.

  • Similar to the Hamiltonian Cycle problem, finding a Hamiltonian Path in a general graph is also NP-complete and can be challenging. However, it is often a more easier problem than finding a Hamiltonian Cycle.
  • Hamiltonian Paths have applications in various fields, such as finding optimal routes in transportation networks, circuit design, and graph theory research.

Problem Statement

Given an undirected graph, the task is to determine whether the graph contains a Hamiltonian cycle or not. If it contains, then print the path, else print "Solution does not exist".

Examples:

Input: graph[][] = [[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]]

Input graph[][]

Output: 0 1 2 4 3 0

Input: graph[][] = [[0, 1, 0, 1, 0], [1, 0, 1, 1, 1], [0, 1, 0, 0, 1], [1, 1, 0, 0, 0], [0, 1, 1, 0, 0]]

one_img_2
Input graph[][]


Output: Solution Does Not Exists

[Naive Approach] Generate All Configurations

Generate all possible configurations of vertices and print a configuration that satisfies the given constraints. There will be n! (n factorial) configurations. So the overall Time Complexity of this approach will be at least n!.

[Expected Approach] Using Backtracking - O(2^n) Time and

The idea is to use backtracking to determine whether the given graph contains a Hamiltonian Cycle. Initialize an empty path array and place the starting vertex (e.g., vertex 0) at the first position. Recursively try to add the remaining vertices one by one. Before placing a vertex, ensure it is adjacent to the previously added vertex and has not already been used in the path. If a valid vertex is found, proceed forward; otherwise, backtrack and try another option.

Illustrations:

Let's find out the Hamiltonian cycle for the following graph:

Untitled-Diagra-(1)
  • Start with the node 0 .
  • Apply DFS for finding the Hamiltonian path.
  • When base case reach (i.e. total no of node traversed == n (total vertex)):
    • Check whether current node is a neighbour of starting node.
    • As node 2 and node 0 are not neighbours of each other so return from it.
Hamiltonian-Cycle
Starting from start node 0 calling DFS
  • As cycle is not found in path {0, 3, 1, 4, 2}. So, return from node 2, node 4.
file
  • Now, explore another option for node 1 (i.e node 2)
  • When it hits the base condition again check for Hamiltonian cycle
  • As node 4 is not the neighbour of node 0, again cycle is not found then return.
file
  • Return from node 4, node 2, node 1.
file
  • Now, explore other options for node 3.


hamiltonian-1
Hamiltonian Cycle
  • In the Hamiltonian path {0,3,4,2,1,0} we get cycle as node 1 is the neighbour of node 0.
  • So print this cyclic path .
  • This is our Hamiltonian cycle.

Note: The algorithm always begins constructing the cycle from a fixed starting vertex, but in a Hamiltonian cycle, the starting point is arbitrary. To allow flexibility in choosing the starting vertex, minor adjustments are needed so the cycle can initiate from any node rather than a predefined one.

C++
// C++ Code to check whether the given graph
// contains Hamiltonian Cycle using backtracking
#include <bits/stdc++.h>
using namespace std;

// Check if it's valid to place vertex at current position
bool isSafe(int vertex, vector<vector<int>> &graph, 
            vector<int> &path, int pos) {
    
    // The vertex must be adjacent to the previous vertex
    if (!graph[path[pos - 1]][vertex]) {
        return false;
    }

    // The vertex must not already be in the path
    for (int i = 0; i < pos; i++) {
        if (path[i] == vertex) {
            return false;
        }
    }

    return true;
}

// Recursive backtracking to construct Hamiltonian Cycle
bool hamCycleUtil(vector<vector<int>> &graph, 
                  vector<int> &path, int pos, int n) {
    
    // Base case: all vertices are in the path
    if (pos == n) {
        
        // Check if there's an edge from 
        // last to first vertex
        return graph[path[pos - 1]][path[0]];
    }

    // Try all possible vertices as next candidate
    for (int v = 1; v < n; v++) {
        if (isSafe(v, graph, path, pos)) {
            path[pos] = v;

            if (hamCycleUtil(graph, path, pos + 1, n)) {
                return true;
            }

            // Backtrack if v doesn't lead to a solution
            path[pos] = -1;
        }
    }

    return false;
}

// Initialize path and invoke backtracking function
vector<int> hamCycle(vector<vector<int>> &graph) {
    int n = graph.size();
    vector<int> path(n, -1);

    // Start path with vertex 0
    path[0] = 0;

    if (!hamCycleUtil(graph, path, 1, n)) {
        return {-1};
    }

    return path;
}

// Driver Code
int main() {
    
    // Representation of the given graph
    //    (0)-(1)-(2) 
    //     |  / \  | 
    //     | /   \ | 
    //     |/     \| 
    //    (3)-----(4)
    vector<vector<int>> graph = {
        {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}
    };

    vector<int> path = hamCycle(graph);
    
    if(path[0] == -1) {
        
        cout << "Solution does not Exist";
    }
    else {
        
        for (int i = 0; i < path.size(); i++) {
           cout << path[i] << " ";
        }

        // Print the first vertex again 
        // to complete the cycle
        cout << path[0];
    }

    return 0;
}
Java
// Java Code to check whether the given graph
// contains Hamiltonian Cycle using backtracking
class GfG {

    // Check if it's valid to place vertex at current position
    static boolean isSafe(int vertex, int[][] graph, 
                          int[] path, int pos) {
        
        // The vertex must be adjacent to the previous vertex
        if (graph[path[pos - 1]][vertex] == 0) {
            return false;
        }

        // The vertex must not already be in the path
        for (int i = 0; i < pos; i++) {
            if (path[i] == vertex) {
                return false;
            }
        }

        return true;
    }

    // Recursive backtracking to construct Hamiltonian Cycle
    static boolean hamCycleUtil(int[][] graph, int[] path, 
                                int pos, int n) {
        
        // Base case: all vertices are in the path
        if (pos == n) {
            
            // Check if there's an edge from 
            // last to first vertex
            return graph[path[pos - 1]][path[0]] == 1;
        }

        // Try all possible vertices as next candidate
        for (int v = 1; v < n; v++) {
            if (isSafe(v, graph, path, pos)) {
                path[pos] = v;

                if (hamCycleUtil(graph, path, pos + 1, n)) {
                    return true;
                }

                // Backtrack if v doesn't lead to a solution
                path[pos] = -1;
            }
        }

        return false;
    }

    // Initialize path and invoke backtracking function
    static int[] hamCycle(int[][] graph) {
        int n = graph.length;
        int[] path = new int[n];
        for (int i = 0; i < n; i++) {
            path[i] = -1;
        }

        // Start path with vertex 0
        path[0] = 0;

        if (!hamCycleUtil(graph, path, 1, n)) {
            return new int[]{-1};
        }

        return path;
    }

    // Driver Code
    public static void main(String[] args) {

        // Representation of the given graph
        //    (0)-(1)-(2) 
        //     |  / \  | 
        //     | /   \ | 
        //     |/     \| 
        //    (3)-----(4)
        int[][] graph = {
            {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}
        };

        int[] path = hamCycle(graph);

        if (path[0] == -1) {
            System.out.print("Solution does not Exist");
        } else {
            for (int i = 0; i < path.length; i++) {
                System.out.print(path[i] + " ");
            }

            // Print the first vertex again 
            // to complete the cycle
            System.out.print(path[0]);
        }
    }
}
Python
# Python Code to check whether the given graph
# contains Hamiltonian Cycle using backtracking

# Check if it's valid to place vertex at current position
def isSafe(vertex, graph, path, pos):
    
    # The vertex must be adjacent to the previous vertex
    if not graph[path[pos - 1]][vertex]:
        return False

    # The vertex must not already be in the path
    for i in range(pos):
        if path[i] == vertex:
            return False

    return True

# Recursive backtracking to construct Hamiltonian Cycle
def hamCycleUtil(graph, path, pos, n):
    
    # Base case: all vertices are in the path
    if pos == n:
        
        # Check if there's an edge from 
        # last to first vertex
        return graph[path[pos - 1]][path[0]]

    # Try all possible vertices as next candidate
    for v in range(1, n):
        if isSafe(v, graph, path, pos):
            path[pos] = v

            if hamCycleUtil(graph, path, pos + 1, n):
                return True

            # Backtrack if v doesn't lead to a solution
            path[pos] = -1

    return False

# Initialize path and invoke backtracking function
def hamCycle(graph):
    n = len(graph)
    path = [-1] * n

    # Start path with vertex 0
    path[0] = 0

    if not hamCycleUtil(graph, path, 1, n):
        return [-1]

    return path

# Driver Code
if __name__ == "__main__":
    
    # Representation of the given graph
    #    (0)-(1)-(2) 
    #     |  / \  | 
    #     | /   \ | 
    #     |/     \| 
    #    (3)-----(4)
    graph = [
        [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]
    ]

    path = hamCycle(graph)

    if path[0] == -1:
        print("Solution does not Exist")
    else:
        for i in range(len(path)):
            print(path[i], end=" ")

        # Print the first vertex again 
        # to complete the cycle
        print(path[0])
C#
// C# Code to check whether the given graph
// contains Hamiltonian Cycle using backtracking
using System;

class GfG {

    // Check if it's valid to place vertex at current position
    static bool isSafe(int vertex, int[,] graph,
                       int[] path, int pos) {
        
        // The vertex must be adjacent to the previous vertex
        if (graph[path[pos - 1], vertex] == 0) {
            return false;
        }

        // The vertex must not already be in the path
        for (int i = 0; i < pos; i++) {
            if (path[i] == vertex) {
                return false;
            }
        }

        return true;
    }

    // Recursive backtracking to construct Hamiltonian Cycle
    static bool hamCycleUtil(int[,] graph, int[] path,
                             int pos, int n) {
        
        // Base case: all vertices are in the path
        if (pos == n) {
            
            // Check if there's an edge from 
            // last to first vertex
            return graph[path[pos - 1], path[0]] == 1;
        }

        // Try all possible vertices as next candidate
        for (int v = 1; v < n; v++) {
            if (isSafe(v, graph, path, pos)) {
                path[pos] = v;

                if (hamCycleUtil(graph, path, pos + 1, n)) {
                    return true;
                }

                // Backtrack if v doesn't lead to a solution
                path[pos] = -1;
            }
        }

        return false;
    }

    // Initialize path and invoke backtracking function
    static int[] hamCycle(int[,] graph) {
        int n = graph.GetLength(0);
        int[] path = new int[n];
        for (int i = 0; i < n; i++) {
            path[i] = -1;
        }

        // Start path with vertex 0
        path[0] = 0;

        if (!hamCycleUtil(graph, path, 1, n)) {
            return new int[] { -1 };
        }

        return path;
    }

    // Driver Code
    static void Main() {

        // Representation of the given graph
        //    (0)-(1)-(2) 
        //     |  / \  | 
        //     | /   \ | 
        //     |/     \| 
        //    (3)-----(4)
        int[,] graph = {
            {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}
        };

        int[] path = hamCycle(graph);

        if (path[0] == -1) {
            Console.Write("Solution does not Exist");
        } else {
            for (int i = 0; i < path.Length; i++) {
                Console.Write(path[i] + " ");
            }

            // Print the first vertex again 
            // to complete the cycle
            Console.Write(path[0]);
        }
    }
}
JavaScript
// JavaScript Code to check whether the given graph
// contains Hamiltonian Cycle using backtracking

// Check if it's valid to place vertex at current position
function isSafe(vertex, graph, path, pos) {
    
    // The vertex must be adjacent to the previous vertex
    if (!graph[path[pos - 1]][vertex]) {
        return false;
    }

    // The vertex must not already be in the path
    for (let i = 0; i < pos; i++) {
        if (path[i] === vertex) {
            return false;
        }
    }

    return true;
}

// Recursive backtracking to construct Hamiltonian Cycle
function hamCycleUtil(graph, path, pos, n) {
    
    // Base case: all vertices are in the path
    if (pos === n) {
        
        // Check if there's an edge from 
        // last to first vertex
        return graph[path[pos - 1]][path[0]];
    }

    // Try all possible vertices as next candidate
    for (let v = 1; v < n; v++) {
        if (isSafe(v, graph, path, pos)) {
            path[pos] = v;

            if (hamCycleUtil(graph, path, pos + 1, n)) {
                return true;
            }

            // Backtrack if v doesn't lead to a solution
            path[pos] = -1;
        }
    }

    return false;
}

// Initialize path and invoke backtracking function
function hamCycle(graph) {
    const n = graph.length;
    const path = new Array(n).fill(-1);

    // Start path with vertex 0
    path[0] = 0;

    if (!hamCycleUtil(graph, path, 1, n)) {
        return [-1];
    }

    return path;
}

// Driver Code

// Representation of the given graph
//    (0)-(1)-(2) 
//     |  / \  | 
//     | /   \ | 
//     |/     \| 
//    (3)-----(4)
const graph = [
    [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]
];

const path = hamCycle(graph);

if (path[0] === -1) {
    console.log("Solution does not Exist");
} else {
    for (let i = 0; i < path.length; i++) {
        process.stdout.write(path[i] + " ");
    }

    // Print the first vertex again 
    // to complete the cycle
    console.log(path[0]);
}

Output
0 1 2 4 3 0

Time Complexity: O(n!), backtracking tries all permutations of n vertices. Each recursive call explores (n − 1) possibilities for remaining vertices.
Space Complexity: O(n), path array takes O(n) space, and recursion stack also takes O(n).


Article Tags :
Practice Tags :

Similar Reads