PROBLEM SOLVING - BACKTRACKING IN C INTRODUCTION
Backtracking Basics in C
Backtracking Definition
Backtracking is a systematic way to try different solutions and backtrack when a solution doesn't work. Key characteristics:
- Recursive - Uses recursion to explore possibilities
- Pruning - Eliminates invalid paths early
- Exhaustive - Explores all possible solutions
- Undo operation - Reverts changes when backtracking
// General structure:
void backtrack(solution, parameters) {
if (solution_complete) {
store_solution();
return;
}
for (all possible choices) {
if (choice is valid) {
make_choice(choice);
backtrack(solution, parameters);
undo_choice(choice); // Backtrack
}
}
}
Backtracking Applications
Backtracking is fundamental in algorithm design with various applications:
- Combinatorial problems (permutations, combinations)
- Constraint satisfaction problems
- Puzzle solving (Sudoku, N-Queens, etc.)
- Graph problems (path finding, coloring)
- Subset and partition problems
- Game playing algorithms
- Optimization problems
Backtracking Components
Key components of a backtracking algorithm:
1. Choice: The options available at each decision point
2. Constraints: Conditions that must be satisfied
3. Goal: Criteria for a complete solution
4. Recursive exploration: Try choices and backtrack
5. Pruning: Eliminate invalid paths early
Common Backtracking Problems
Classic problems solved with backtracking:
- N-Queens Problem - Place N queens on chessboard
- Sudoku Solver - Fill Sudoku grid
- Permutations - Generate all permutations
- Subset Sum - Find subsets with given sum
- Graph Coloring - Color vertices with constraints
- Knapsack Problem - Optimal item selection
Backtracking vs Other Techniques
Comparison with other algorithmic approaches:
Backtracking:
- Explores all possibilities
- Uses recursion
- Prunes invalid paths
- Good for multiple solutions
Dynamic Programming:
- Stores subproblem solutions
- Bottom-up or top-down
- Good for optimal solutions
Divide and Conquer:
- Breaks into smaller problems
- Solves independently
- Combines solutions
- Good for parallelization
PROBLEM SOLVING - BACKTRACKING TRICKS
Backtracking Approaches
| # | Technique | Use Case | Approach | Complexity | Examples |
|---|---|---|---|---|---|
| 1 | Recursive Backtracking | General backtracking problems | Use recursion to explore choices and backtrack | O(b^d) |
|
| 2 | Pruning | Optimize backtracking by eliminating paths | Detect and stop exploring invalid paths early | Reduces O(b^d) |
|
| 3 | Memoization | Avoid recomputation of subproblems | Cache results of subproblems to reuse | O(n) |
|
| 4 | Iterative Backtracking | Avoid recursion stack limits | Use explicit stack to simulate recursion | Same as recursive |
|
| 5 | Branch and Bound | Optimization problems | Prune using cost bounds for optimal solution | O(b^d) |
|
Common Backtracking Operations
Generate Permutations
void permute(char *str, int l, int r) {
if (l == r) {
printf("%s\n", str);
} else {
for (int i = l; i <= r; i++) {
swap(str+l, str+i);
permute(str, l+1, r);
swap(str+l, str+i); // Backtrack
}
}
}
N-Queens Solution
bool solveNQUtil(int board[N][N], int col) {
if (col >= N) return true;
for (int i = 0; i < N; i++) {
if (isSafe(board, i, col)) {
board[i][col] = 1;
if (solveNQUtil(board, col+1))
return true;
board[i][col] = 0; // Backtrack
}
}
return false;
}
Sudoku Solver
bool solveSudoku(int grid[N][N]) {
int row, col;
if (!findEmpty(grid, &row, &col))
return true;
for (int num = 1; num <= 9; num++) {
if (isSafe(grid, row, col, num)) {
grid[row][col] = num;
if (solveSudoku(grid)) return true;
grid[row][col] = 0; // Backtrack
}
}
return false;
}
Subset Sum
void subsetSum(int set[], int n, int sum,
int subset[], int size, int total) {
if (total == sum) {
printSubset(subset, size);
return;
}
for (int i = 0; i < n; i++) {
if (total + set[i] <= sum) {
subset[size] = set[i];
subsetSum(set, n, sum, subset,
size+1, total+set[i]);
// Backtrack implicitly by not including
}
}
}
Graph Coloring
bool graphColoring(int graph[V][V], int m,
int color[], int v) {
if (v == V) return true;
for (int c = 1; c <= m; c++) {
if (isSafe(v, graph, color, c)) {
color[v] = c;
if (graphColoring(graph, m, color, v+1))
return true;
color[v] = 0; // Backtrack
}
}
return false;
}
Word Break
bool wordBreak(char *str, char *dict[], int n) {
if (strlen(str) == 0) return true;
for (int i = 1; i <= strlen(str); i++) {
char prefix[i+1];
strncpy(prefix, str, i);
prefix[i] = '\0';
if (inDict(prefix, dict, n) &&
wordBreak(str+i, dict, n)) {
return true;
}
}
return false;
}
Advanced Backtracking Techniques
| # | Technique | Description | Use Case |
|---|---|---|---|
| 1 | Constraint Propagation | Reduce search space by enforcing constraints early | Sudoku, CSPs |
| 2 | Branch and Bound | Prune using upper/lower bounds for optimization | TSP, Knapsack |
| 3 | Memoization | Cache results to avoid recomputation | DP with backtracking |
| 4 | Heuristic Ordering | Order choices by likelihood of success | Optimization problems |
| 5 | Iterative Deepening | Combine DFS with BFS for depth-limited search | Large state spaces |
| 6 | Min-Max with Alpha-Beta | Game tree search with pruning | Game playing |
| 7 | Random Restarts | Multiple runs with different initial states | Local optima problems |
| 8 | Symmetry Breaking | Avoid exploring symmetric solutions | Combinatorial problems |
| 9 | Dynamic Variable Ordering | Choose next variable based on current state | Constraint satisfaction |
| 10 | Value Ordering | Prioritize values likely to lead to solution | Optimization problems |
| 11 | Look-Ahead | Check future implications of current choice | Constraint propagation |
| 12 | Conflict-Directed Backjumping | Jump back to source of conflict | Constraint satisfaction |
Related Backtracking Resources