Data Structures & Algorithms – Backtracking (e.g. n-queens problem, Sudoku)

Backtracking is a general algorithm for finding all solutions by incrementally building candidates to the solutions, and abandoning a candidate (“backtracking”) as soon as it is determined that the candidate cannot possibly be completed to a valid solution. Backtracking is often used to solve problems that involve finding all possible solutions within a given constraints. Some examples of backtracking algorithms include:

  1. N-Queens problem: The N-Queens problem is a classic problem of placing N queens on an NxN chessboard such that no two queens attack each other. This problem can be solved using backtracking by incrementally placing queens on the chessboard and checking for conflicts. If a conflict is found, the algorithm will backtrack and try a different position for the queen. The time complexity of the N-Queens problem is O(N!)

Here is an example of the N-Queens problem solved using backtracking in Python:

def is_valid(board, row, col, n):
    for i in range(row):
        if board[i] == col or \
            abs(board[i] - col) == abs(i - row):
            return False
    return True

def n_queens(board, row, n):
    if row == n:
        print(board)
        return
    for col in range(n):
        if is_valid(board, row, col, n):
            board[row] = col
            n_queens(board, row + 1, n)

n = 4
board = [0] * n
n_queens(board, 0, n)
  1. Sudoku: Sudoku is a number-placement puzzle where the goal is to fill a 9×9 grid with digits so that each column, each row, and each of the nine 3×3 sub-grids that compose the grid contains all of the digits from 1 to 9. This problem can be solved using backtracking by incrementally filling in the grid and checking for conflicts. If a conflict is found, the algorithm will backtrack and try a different number. The time complexity of the Sudoku solver is O(N!)

Here is an example of a Sudoku solver using backtracking in Python:

def is_valid(grid, row, col, num):
    for i in range(9):
        if grid[row][i] == num or grid[i][col] == num:
            return False
    row_start = (row // 3) * 3
    col_start = (col // 3) * 3
    for i in range(3):
        for j in range(3):
            if grid[row_start + i][col_start + j] == num:
                return False
    return True

def sudoku(grid, row, col):
    if row == 9:
        return True
    if col == 9:
        return sudoku(grid, row + 1, 0)
    if grid[row][col] != 0:
        return sudoku(grid, row, col + 1)
    for num in range(1, 10):
        if is_valid(grid, row, col, num):
            grid[row][col] = num
            if sudoku(grid, row, col + 1):
                return True
            grid[row][col] = 0
    return False

grid = [[5, 3, 0,</code>0, 7, 0, 0, 0, 0],
[6, 0, 0, 1, 9, 5, 0, 0, 0],
[0, 9, 8, 0, 0, 0, 0, 6, 0],
[8, 0, 0, 0, 6, 0, 0, 0, 3],
[4, 0, 0, 8, 0, 3, 0, 0, 1],
[7, 0, 0, 0, 2, 0, 0, 0, 6],
[0, 6, 0, 0, 0, 0, 2, 8, 0],
[0, 0, 0, 4, 1, 9, 0, 0, 5],
[0, 0, 0, 0, 8, 0, 0, 7, 9]]

sudoku(grid, 0, 0)
for row in grid:
print(row)

Both examples can be implemented in various programming languages such as Python, JavaScript, Java and Rust. Keep in mind that the examples provided are simplified versions of the original algorithms and may not be suitable for production use. In conclusion, Backtracking is a general algorithm for finding all solutions by incrementally building candidates to the solutions, and abandoning a candidate as soon as it is determined that the candidate cannot possibly be completed to a valid solution. The n-queens problem and Sudoku problem are examples of backtracking algorithm that can be used to solve problems that involve finding all possible solutions within a given constraints. Both algorithms have a time complexity of O(N!) which makes them inefficient for large inputs. However, it can be optimized by adding constraints or heuristics to the search.