Backtracking And Branch And Bound Algorithm Hamiltonian Cycle And Subset Sum Problem Complete Guide

 Last Update:2025-06-22T00:00:00     .NET School AI Teacher - SELECT ANY TEXT TO EXPLANATION.    8 mins read      Difficulty-Level: beginner

Understanding the Core Concepts of Backtracking and Branch and Bound Algorithm Hamiltonian Cycle and Subset Sum Problem


Backtracking and Branch and Bound Algorithms: Hamiltonian Cycle and Subset Sum Problem

Introduction to Backtracking

Backtracking is a systematic algorithmic technique used in solving constraint satisfaction problems such as the Hamiltonian Cycle and Subset Sum problems. It works by incrementally constructing candidates to the solution and abandoning a candidate ("backtrack") as soon as it determines that this candidate cannot possibly lead to a valid solution. The core idea is to explore possible solutions and prune search paths early whenever possible.

Hamiltonian Cycle Problem using Backtracking

The Hamiltonian Cycle problem asks whether there exists a cycle in a graph that visits each vertex exactly once (except the starting vertex, which it also ends at). This problem is NP-complete. Backtracking can be used effectively to find such cycles.

Algorithm Steps:

  1. Start from Any Vertex: Begin from a vertex and mark it as visited.
  2. Explore Possible Neighbors Recursively: From the current vertex, recursively try to visit its unvisited neighbors forming a cycle.
  3. Check Completion Condition: If all vertices are visited, check if there’s an edge back to the starting vertex to complete the cycle.
  4. Backtrack If Necessary: If no cycle can be completed, backtrack to the previous state and try another path.

Important Information:

  • Complexity: The time complexity is exponential, O(n!), where n is the number of vertices.
  • Pruning: Prune paths early whenever adding a vertex does not lead to a potential solution.
  • Graph Representation: Use adjacency lists or matrices for efficient neighbor searches.
  • Cycle Detection: Ensure that no vertex is visited more than once except the start/finish vertex of the cycle.

Example: Consider a simple graph: Vertices = {A, B, C, D} Edges = {(A,B), (B,C), (C,D), (D,A), (B,D)} Backtracking would start from A, mark it visited, move to B, then C, and finally attempt to return to A via D to form a Hamiltonian Cycle if possible.

Subset Sum Problem using Backtracking

The Subset Sum problem involves a set of integers and a target sum; the goal is to find a subset whose sum equals the target. This problem is also NP-complete.

Algorithm Steps:

  1. Sort the Numbers (Optional): Sorting helps in pruning more effectively when the numbers are large.
  2. Include-or-Exclude Approach: For each number, decide whether to include it or exclude it from the subset and move recursively for the remaining numbers.
  3. Check Sum Equality: If at any point the current subset sum equals the target, a valid solution is found.
  4. Backtrack If Necessary: If including or excluding a number does not lead to a solution, backtrack to the previous choice.

Important Information:

  • Complexity: The time complexity is O(2^n), where n is the number of elements, making it impractical for large sets.
  • Pruning: Prune the branches where the current subset sum exceeds the target.
  • Subset Representation: Use bitmasking for efficient subset representation and sum calculation.

Example: Given a set {3, 34, 4, 12, 5, 2} and target sum 9. Backtracking explores subsets like {3, 4, 2} to see if their sum equals 9.

Introduction to Branch and Bound

Branch and Bound is another algorithm used mainly for numerical and combinatorial optimization problems. It systematically searches all candidate solutions but prunes those that do not satisfy certain constraints or bound calculations.

Hamiltonian Cycle Problem using Branch and Bound

Using Branch and Bound for the Hamiltonian Cycle problem is more complex due to the non-numerical nature of the problem, but it can still be effectively applied. Here, bounds are usually derived based on heuristic methods rather than direct calculations.

Algorithm Steps:

  1. Generate Initial Bound: Start with a feasible bound, e.g., shortest path between all pairs of vertices.
  2. Create Initial Set of Nodes: Form a initial set containing all nodes with their associated bounds.
  3. Choose Node Subset: At each step, choose the node with the lowest bound to explore further.
  4. Generate New Node Subsets: From the chosen node, generate new subsets by adding adjacent nodes.
  5. Update Bounds: Calculate new bounds and prune subsets where bounds exceed the feasible minimum.
  6. Check for Cycle: If a cycle is formed, check if all nodes are visited once (except starting one).
  7. Repeat Until Solution Found: Continue until a Hamiltonian cycle is formed or all promising subsets are exhausted.

Important Information:

  • Feasible Bound Calculation: Heuristics play a crucial role in calculating initial and updated bounds.
  • Pruning Strategy: Use bounds to aggressively prune unnecessary subsets before exploring fully.
  • Complexity: Generally better performance than pure backtracking due to pruning strategy.

Subset Sum Problem using Branch and Bound

In the context of Subset Sum, Branch and Bound uses a more structured approach based on upper and lower bounds to prune subsets.

Algorithm Steps:

  1. Generate Initial Upper/Lower Bounds: Start with an initial upper/lower bound based on sums of the sets.
  2. Queue Initialization: Form a queue containing subsets initially.
  3. Sort Queue: Sort the queue based on bound calculations.
  4. Expand Subset: Pick the subset with the best bound and expand it by two possibilities: including the next item or excluding the next item.
  5. Compute New Upper/Lower Bounds: Recalculate the bounds after each expansion.
  6. Compare Target: Compare the current subset sum to the target and add promising subsets to queue.
  7. Prune Subsets: Discard subsets where the bounds indicate they cannot be part of a solution.
  8. Repeat Until Solution Found: Continue expanding and pruning until a subset is found equal to the target.

Important Information:

  • Upper/Lower Bound Calculation: These bounds help in efficiently determining if a subset should be further explored.
  • Complexity: Typically much faster than backtracking, especially for larger datasets due to bound-based pruning.
  • Sorting Strategy: Sorting the input set can improve efficiency and pruning effectiveness.
  • Priority Queue Use: Implementing the priority queue based on bounds ensures quicker exploration of promising subsets.

Example: Given a set {3, 34, 4, 12, 5, 2} and target sum 9. The initial bounds might consider partial sums of the set to guide the exploration and prune paths quickly.


General Keywords Related to the Topic

  1. Algorithm
  2. Constraint Satisfaction
  3. Hamiltonian Cycle
  4. Subset Sum Problem
  5. Backtracking
  6. Branch and Bound
  7. Recursion
  8. Pruning
  9. Graph Theory
  10. Adacency List
  11. Adacency Matrix
  12. Bitmasking
  13. NP-Complete
  14. Heuristic
  15. Upper Bound
  16. Lower Bound
  17. Priority Queue
  18. Exponential Complexity
  19. Feasible Solution
  20. Solution Space

Online Code run

🔔 Note: Select your programming language to check or run code at

💻 Run Code Compiler

Step-by-Step Guide: How to Implement Backtracking and Branch and Bound Algorithm Hamiltonian Cycle and Subset Sum Problem

Hamiltonian Cycle Problem

Problem Statement

The Hamiltonian Cycle problem is to determine whether a graph contains a cycle that visits each vertex exactly once and returns to the starting vertex.

Backtracking Algorithm

Here is how you can implement the Backtracking algorithm to solve the Hamiltonian Cycle problem in Python:

class HamiltonianCycle:
    def __init__(self, vertices):
        self.graph = [[0 for _ in range(vertices)] for _ in range(vertices)]
        self.V = vertices

    def is_valid(self, v, pos, path):
        # Check if the vertex is adjacent to the last included vertex in path
        if self.graph[path[pos - 1]][v] == 0:
            return False

        # Check if the vertex is not already included in the path
        if v in path:
            return False

        return True

    def ham_cycle_util(self, path, pos):
        # Base case: if all vertices are included in the path
        if pos == self.V:
            # Check if there is an edge from the last included vertex to the first vertex
            if self.graph[path[pos - 1]][path[0]] == 1:
                return True
            else:
                return False

        # Try different vertices as the next candidate in the Hamiltonian Cycle
        for v in range(1, self.V):
            if self.is_valid(v, pos, path):
                path[pos] = v

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

                # Backtrack
                path[pos] = -1

        return False

    def ham_cycle(self):
        path = [-1] * self.V

        # Let us put vertex 0 as the first vertex in the path. If there is a Hamiltonian Cycle, 
        # then the path can be started from any vertex
        path[0] = 0

        if not self.ham_cycle_util(path, 1):
            print("Solution does not exist")
            return False

        self.print_solution(path)
        return True

    def print_solution(self, path):
        print("Solution Exists: Following is one Hamiltonian Cycle")
        for vertex in path:
            print(vertex, end=" ")
        print(path[0], "\n")

# Example usage:
# Create the graph as an adjacency matrix
g1 = HamiltonianCycle(5)
g1.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],
]

g1.ham_cycle()

Branch and Bound Algorithm

The Branch and Bound algorithm for the Hamiltonian Cycle is more complex and involves maintaining a lower bound to reduce the search space. However, it is not as commonly used for this problem as Backtracking. Below is a simplified version using a similar approach:

from heapq import heappop, heappush

class HamiltonianCycleBranchAndBound:
    def __init__(self, vertices):
        self.graph = [[0 for _ in range(vertices)] for _ in range(vertices)]
        self.V = vertices

    def calculate_lower_bound(self, path, path_length):
        last_vertex = path[-1]
        min_cost = float('inf')
        for i in range(self.V):
            if i not in path and self.graph[last_vertex][i] > 0:
                min_cost = min(min_cost, self.graph[last_vertex][i])
        return min_cost

    def branch_and_bound(self):
        priority_queue = []
        initial_path = [0]
        initial_lower_bound = sum(self.calculate_lower_bound(initial_path, len(initial_path)) for _ in range(self.V))
        heappush(priority_queue, (initial_lower_bound, initial_path))

        while priority_queue:
            lower_bound, path = heappop(priority_queue)

            if len(path) == self.V:
                if self.graph[path[-1]][path[0]] > 0:
                    path.append(0)
                    return path

            if lower_bound == float('inf'):
                return None

            last_vertex = path[-1]
            remaining_vertices = [i for i in range(self.V) if i not in path]

            for vertex in remaining_vertices:
                new_path = path + [vertex]
                new_lower_bound = lower_bound + self.graph[last_vertex][vertex] + self.calculate_lower_bound(new_path, len(new_path))
                heappush(priority_queue, (new_lower_bound, new_path))

        return None

    def print_solution(self, path):
        if path is None:
            print("Solution does not exist")
        else:
            print("Solution Exists: Following is one Hamiltonian Cycle")
            for vertex in path:
                print(vertex, end=" ")

# Example usage:
# Create the graph as an adjacency matrix
g2 = HamiltonianCycleBranchAndBound(5)
g2.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],
]

g2.print_solution(g2.branch_and_bound())

Subset Sum Problem

Problem Statement

The Subset Sum problem is to find a subset of a given set of integers that adds up to a specific target sum.

Backtracking Algorithm

def is_subset_sum_util(numbers, n, target, path, results):
    if target == 0:
        results.append(list(path))
        return True

    if target < 0 or n == 0:
        return False

    # Inclusion
    path.append(numbers[n - 1])
    found_inclusion = is_subset_sum_util(numbers, n - 1, target - numbers[n - 1], path, results)
    path.pop()

    # Exclusion
    found_exclusion = is_subset_sum_util(numbers, n - 1, target, path, results)

    return found_inclusion or found_exclusion

def is_subset_sum(numbers, target):
    results = []
    is_subset_sum_util(numbers, len(numbers), target, [], results)
    return results

# Example usage:
numbers = [3, 34, 4, 12, 5, 2]
target = 9
results = is_subset_sum(numbers, target)
if results:
    print("Subset(s) that sum to", target, "are:")
    for subset in results:
        print(subset)
else:
    print("No subset(s) found that sum to", target)

Branch and Bound Algorithm

Here is a simplified Branch and Bound algorithm for the Subset Sum problem using a priority queue.

Top 10 Interview Questions & Answers on Backtracking and Branch and Bound Algorithm Hamiltonian Cycle and Subset Sum Problem

Backtracking and Branch and Bound Algorithms

1. What is the Backtracking algorithm, and how does it differ from the Branch and Bound algorithm?

  • Backtracking is a general algorithmic technique used to find all (or some) solutions to computational problems, notably constraint satisfaction problems, by incrementally building candidates to the solutions and abandoning a candidate as soon as it determines that it cannot possibly lead to a valid solution.
  • Branch and Bound is a method used for solving discrete and especially combinatorial optimization problems. It systematically explores the solution space by maintaining a tree of subproblems. It divides the problem into a tree of subproblems and then, using bounds, it eliminates parts of the tree that would not yield solutions better than the best one already found.

2. How can the Backtracking algorithm be applied to the Hamiltonian Cycle problem?

  • The Hamiltonian Cycle problem involves finding a cycle in a graph that visits each vertex exactly once and returns to the starting vertex. Using backtracking, you start from a vertex and explore possible paths, marking vertices as visited. If a vertex is visited, you backtrack and try another path until you find a valid Hamiltonian Cycle or determine that none exists.

3. Can you explain the Branch and Bound approach to solving the Hamiltonian Cycle problem?

  • In the Branch and Bound approach for the Hamiltonian Cycle problem, the algorithm searches through the solution space using a tree structure. At each node, it checks if the current partial solution can lead to a better solution than the best one found so far (bound). If not, that subtree is pruned, significantly reducing the search space.

4. What is the Subset Sum Problem, and why is it an NP-complete problem?

  • The Subset Sum Problem involves determining if a subset of a given set of integers can sum up to a specified target value. It is NP-complete because it can be reduced to other known NP-complete problems, and no polynomial-time algorithm is known to solve all possible instances of the problem.

5. How does the Backtracking algorithm solve the Subset Sum Problem?

  • The Backtracking algorithm tries all possible subsets of the set of integers to find a subset that sums to the target value. It explores each candidate subset deeply before backtracking to explore another possibility, marking each integer as used or unused.

6. Can Branch and Bound be applied to the Subset Sum Problem, and if so, how?

  • Yes, Branch and Bound can be applied to the Subset Sum Problem. The algorithm builds a tree where each node represents a subset sum problem with a subset of the original set. Using bounds, it can discard branches that cannot lead to a feasible solution, pruning parts of the tree that yield sums higher than the target or less than the remaining elements required to meet the target.

7. How does the time complexity of backtracking compare to branch and bound for the Hamiltonian Cycle and Subset Sum Problems?

  • Backtracking can have exponential time complexity for Hamiltonian Cycle and Subset Sum because it explores all possible combinations. Branch and Bound often has better performance than pure backtracking because of pruning, but in the worst case, it can also be exponential, especially for hard instances of NP-complete problems.

8. What are some improvements or heuristics that can be used to make branch and bound more efficient in solving the Hamiltonian Cycle problem?

  • Heuristics like using a Minimum Spanning Tree (MST) to guide the search or employing dynamic programming techniques can be integrated into branch and bound to reduce complexity.
  • Pruning techniques based on the degree of vertices, lower bounds (e.g., the sum of edge weights), and upper bounds (e.g., the shortest path in a graph) can also significantly decrease the search space.

9. Are there any practical applications of the Hamiltonian Cycle problem?

  • The Hamiltonian Cycle problem has practical applications in various fields, including:
    • Vehicle Routing Problems: Determining the shortest route for delivery vehicles that must visit a set of locations.
    • Scheduling: Finding an optimal schedule for operations or tasks.
    • Telecommunications: Network design and routing.

10. What are some practical applications of the Subset Sum Problem?

  • The Subset Sum Problem has applications in different areas, such as:
    • Knapsack Problems: Optimizing the selection of items to maximize value within weight constraints.
    • Resource Allocation: Allocating limited resources among competing claims.
    • Cryptography: Certain cryptographic systems rely on the computational complexity of the Subset Sum Problem for security.

You May Like This Related .NET Topic

Login to post a comment.