Backtracking PDF
Backtracking PDF
1. The problem has multiple solutions, and we need to explore all possibilities.
Back tracking : 1
3. We can eliminate paths that do not satisfy constraints early.
Concept of Backtracking
Backtracking follows a Depth-First Search (DFS) approach. It works as:
4. If a solution fails, backtrack (undo the last step) and try another path.
Example :
1. Solving Sudoku (Puzzle Solving)
Problem: Fill a 9×9 grid with numbers 1-9 so that no number repeats in any
row, column, or 3×3 subgrid.
👉 Example:
If placing 5 in a cell leads to an invalid Sudoku, we remove it and try another
number.
Back tracking : 2
👉 Example:
If a queen placed in row 3 conflicts with another, we backtrack and try another
column.
Backtracking Role: Starts from each letter, tries forming the word, and
backtracks if a letter sequence fails.
👉 Example:
If searching for "CAT" in a grid, we start at C, try A, and if T is missing, we
backtrack.
👉 Example:
If moving right leads to a dead end, backtrack and try down instead.
👉 Example:
A system generating 6-character passwords tries different letters but backtracks
when a rule is violated.
Back tracking : 3
Problem: AI chooses the best move in a game (e.g., Chess, Tic-Tac-Toe).
👉 Example:
In Chess, if moving a bishop results in losing a queen, AI backtracks and selects a
better move.
Problem Statement:
Given an array of integers, find all subsets whose sum equals a given target.
Python Implementation
python
CopyEdit
def subset_sum(arr, target, index=0, subset=[]):
if sum(subset) == target:
print(subset) # Print valid subset
return
if index >= len(arr):
return
Back tracking : 4
# Exclude current element (backtrack)
subset_sum(arr, target, index + 1, subset)
# Example usage
arr = [2, 3, 5, 7]
target = 7
subset_sum(arr, target)
Output:
csharp
CopyEdit
[2, 5]
[7]
css
CopyEdit
[]
/ \
[2] []
/ \ / \
[2,3] [2] [3] []
/ \ / \ / \ / \
[2,3,5] [2,3] [2,5] [2] [3,5] [3] [5] []
/ \ / \ / \ / \ / \ / \ / \ / \
[2,3,5,7] X [2,5,7] X [2,7] X [3,7] X [5,7] X [7] X
Back tracking : 5
X denotes a path where the sum does not match the target.
Each element has two choices: include or exclude, leading to 2^n recursive
calls.
In the worst case, we explore all subsets before finding the valid ones.
Exclude 2 [] 0 Explore 3
Back tracking : 6
Exclude 3 [] 0 Explore 5
Exclude 5 [] 0 Explore 7
Key Takeaways
1. Backtracking explores all subsets recursively.
O(2n)O(2^n)
python
CopyEdit
subset_sum([2, 3, 5, 7], 7, index=1, subset=[2])
python
CopyEdit
Back tracking : 7
subset_sum([2, 3, 5, 7], 7, index=2, subset=[2, 3])
Moves to index=2 .
python
CopyEdit
subset_sum([2, 3, 5, 7], 7, index=3, subset=[2, 3, 5])
python
CopyEdit
subset_sum([2, 3, 5, 7], 7, index=3, subset=[2, 3])
python
CopyEdit
subset_sum([2, 3, 5, 7], 7, index=4, subset=[2, 3, 7])
python
CopyEdit
Back tracking : 8
subset_sum([2, 3, 5, 7], 7, index=3, subset=[2, 5])
python
CopyEdit
subset_sum([2, 3, 5, 7], 7, index=2, subset=[3])
python
CopyEdit
subset_sum([2, 3, 5, 7], 7, index=3, subset=[7])
Final Output
csharp
CopyEdit
[2, 5]
[7]
Key Takeaways
✅ Backtracking explores both inclusion and exclusion of elements.
Back tracking : 9
✅ Uses recursion to generate all possible subsets.
✅ Stops early when the sum exceeds the target.
✅ Ensures all valid subsets are found without duplicate calculations.
🔹 What is Backtracking?
Backtracking is an algorithmic technique where we:
Back tracking : 10
nums[i], nums[j] = nums[j], nums[i]
print(f"Swapped nums[{i}] with nums[{j}]: {nums}") # Debugging statem
ent
# Example Usage
nums = [1, 2, 3]
print("All Permutations:")
permute(nums)
less
CopyEdit
[1,2,3]
/ | \
[1,2,3] [2,1,3] [3,2,1]
/ \ / \ / \
[1,2,3] [1,3,2] [2,1,3] [2,3,1] [3,2,1] [3,1,2]
Each level represents choosing a different element to place in the current position.
Back tracking : 11
Time Complexity Analysis
Total permutations of n numbers: n!
n!n!
O(n!×n)O(n! \times n)
O(n!)O(n!)
Back tracking : 12
Each permutation requires O(N) swaps and recursive calls.
Space Complexity:
O(N) recursive calls (due to function call stack).
🔹 Summary
✅ Uses backtracking to explore all permutations.
✅ Swaps elements to generate unique orderings.
✅ Backtracks to restore the original state.
✅ Time Complexity: O(N * N!) (efficient for small N).
Back tracking : 13
🔹 Given Code
python
CopyEdit
def generate_subsets(nums, index=0, current_subset=[], result=[]):
print(f"Called with index={index}, current_subset={current_subset}") # Deb
ugging print
if index == len(nums):
result.append(current_subset[:]) # Store a copy of the current subset
print(f"Subset completed: {current_subset} -> Added to result\n") # Deb
ugging print
return
return result
# Example Usage
nums = [1, 8, 7]
print("All Unique Subsets:")
Back tracking : 14
print(generate_subsets(nums))
plaintext
CopyEdit
nums = [1, 8, 7]
plaintext
CopyEdit
generate_subsets([1, 8, 7], index=0, current_subset=[])
Two choices:
1️⃣
Exclude → Move to
1 index = 1
plaintext
CopyEdit
generate_subsets([1, 8, 7], index=1, current_subset=[])
Back tracking : 15
Two choices:
1️⃣
Exclude → Move to
8 index = 2
plaintext
CopyEdit
generate_subsets([1, 8, 7], index=2, current_subset=[])
Two choices:
1️⃣
Exclude → Move to
7 index = 3
plaintext
CopyEdit
generate_subsets([1, 8, 7], index=3, current_subset=[])
🔄 Backtracking Process
1. Backtrack from [1, 8, 7] → Remove 7
🔹
Back tracking : 16
🔹 Full Execution Trace
Below is the full decision tree showing how the function explores all subsets:
plaintext
CopyEdit
Start with: []
├── Exclude 1 → []
│ ├── Exclude 8 → []
│ │ ├── Exclude 7 → []
│ │ │ ├── (Base case: Add []) ✅
│ │ ├── Include 7 → [7]
│ │ │ ├── (Base case: Add [7]) ✅
│ ├── Include 8 → [8]
│ │ ├── Exclude 7 → [8]
│ │ │ ├── (Base case: Add [8]) ✅
│ │ ├── Include 7 → [8,7]
│ │ │ ├── (Base case: Add [8,7]) ✅
├── Include 1 → [1]
│ ├── Exclude 8 → [1]
│ │ ├── Exclude 7 → [1]
│ │ │ ├── (Base case: Add [1]) ✅
│ │ ├── Include 7 → [1,7]
│ │ │ ├── (Base case: Add [1,7]) ✅
│ ├── Include 8 → [1,8]
│ │ ├── Exclude 7 → [1,8]
│ │ │ ├── (Base case: Add [1,8]) ✅
│ │ ├── Include 7 → [1,8,7]
│ │ │ ├── (Base case: Add [1,8,7]) ✅
At each step:
✅
We exclude first, then include.
Back tracking : 17
✅ Backtracking ensures all possibilities are explored.
🔹 Final Output (All Subsets)
plaintext
CopyEdit
[]
[7]
[8]
[8, 7]
[1]
[1, 7]
[1, 8]
[1, 8, 7]
Space Complexity:
O(N) for the recursive call stack.
🔹 Summary
✅ Uses backtracking to explore all subsets.
✅ Recursive function with include/exclude choices.
✅ Backtracks to restore original state.
Back tracking : 18
✅ Time Complexity: O(2^N) (Exponential growth).
Backtracking Approach
The code will generate all possible combinations:
Python Code
python
CopyEdit
def backtrack(n, k, start, path, result):
if len(path) == k:
result.append(path[:])
return
# Example Usage:
n=4
k=2
Back tracking : 19
print(combine(n, k))
Output
python
CopyEdit
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
Backtracking Tree
scss
CopyEdit
Start with []
├── Add 1 → [1]
│ ├── Add 2 → [1,2] ✅
(Valid)
│ ├── Remove 2 → [1]
│ ├── Add 3 → [1,3] ✅ (Valid)
│ ├── Remove 3 → [1]
│ ├── Add 4 → [1,4] ✅ (Valid)
│ ├── Remove 4 → [1]
│ ├── Remove 1 → []
├── Add 2 → [2]
│ ├── Add 3 → [2,3] ✅
(Valid)
│ ├── Remove 3 → [2]
│ ├── Add 4 → [2,4] ✅ (Valid)
│ ├── Remove 4 → [2]
│ ├── Remove 2 → []
├── Add 3 → [3]
│ ├── Add 4 → [3,4] (Valid) ✅
│ ├── Remove 4 → [3]
│ ├── Remove 3 → []
Back tracking : 20
├── Add 4 → [4] (No more numbers left)
Pick numbers one by one and ensure combinations have exactly k=3
elements.
Backtrack when we reach the required size, removing the last element and
trying another number.
Start with []
├── Add 1 → [1]
│ ├── Add 2 → [1,2]
│ │ ├── Add 3 → [1,2,3] ✅
(Valid)
│ │ ├── Remove 3 → [1,2]
│ │ ├── Add 4 → [1,2,4] ✅
(Valid)
│ │ ├── Remove 4 → [1,2]
│ ├── Remove 2 → [1]
│ ├── Add 3 → [1,3]
│ │ ├── Add 4 → [1,3,4] ✅
(Valid)
│ │ ├── Remove 4 → [1,3]
│ ├── Remove 3 → [1]
│ ├── Add 4 → [1,4] (Not enough elements left)
│ ├── Remove 4 → [1]
Back tracking : 21
│ ├── Remove 1 → []
├── Add 2 → [2]
│ ├── Add 3 → [2,3]
│ │ ├── Add 4 → [2,3,4] ✅
(Valid)
│ │ ├── Remove 4 → [2,3]
│ ├── Remove 3 → [2]
│ ├── Add 4 → [2,4] (Not enough elements left)
│ ├── Remove 4 → [2]
│ ├── Remove 2 → []
├── Add 3 → [3]
│ ├── Add 4 → [3,4] (Not enough elements left)
│ ├── Remove 4 → [3]
│ ├── Remove 3 → []
├── Add 4 → [4] (Not enough elements left)
Python Implementation
python
CopyEdit
def combine(n, k, start=1, current=[]):
if len(current) == k:
print(current) # Print valid combination
return
# Example usage
print("Combinations for n=4, k=2:")
combine(4, 2)
Back tracking : 22
Output (n = 4, k = 2):
csharp
CopyEdit
[1, 2]
[1, 3]
[1, 4]
[2, 3]
[2, 4]
[3, 4]
less
CopyEdit
[]
/ | | \
[1] [2] [3] [4]
/ \ | |
[1,2] [1,3] [1,4]
| | |
[2,3] [2,4] [3,4]
Each level represents picking the next element while maintaining order.
For n = 4, k = 2:
Back tracking : 23
mathematica
CopyEdit
C(4,2) = 4! / (2!(4-2)!) = 6
Back tracking : 24
python
CopyEdit
print("Combinations for n=4, k=3:")
combine(4, 3)
Output:
csharp
CopyEdit
[1, 2, 3]
[1, 2, 4]
[1, 3, 4]
[2, 3, 4]
less
CopyEdit
[]
/ | | \
[1] [2] [3] [4]
/ \ |
[1,2] [1,3] [1,4]
/ | |
[1,2,3] [1,2,4] [1,3,4]
\ \
[2,3,4]
Back tracking : 25
mathematica
CopyEdit
C(4,3) = 4! / (3!(4-3)!) = 4
Back tracking : 26
Backtrack [] Undo last step
Back tracking : 27