🧩 Sudoku Solver – Complete In-Depth Explanation
Sudoku is a popular logic-based number-placement puzzle. The objective is to fill a 9×9 grid with digits so that each column, each row, and each of the nine 3×3 subgrids (also called "boxes" or "regions") contain all of the digits from 1 to 9 exactly once.
📌 Why is Sudoku Important?
- 💡 Demonstrates backtracking algorithms.
- 🧩 Classic constraint satisfaction problem.
- ⚙️ Good example for understanding recursive problem-solving.
📌 Understanding Sudoku with an Example
Here's an example of a Sudoku puzzle:
5 3 . | . 7 . | . . .
6 . . | 1 9 5 | . . .
. 9 8 | . . . | . 6 .
---------------------
8 . . | . 6 . | . . 3
4 . . | 8 . 3 | . . 1
7 . . | . 2 . | . . 6
---------------------
. 6 . | . . . | 2 8 .
. . . | 4 1 9 | . . 5
. . . | . . . | . . .
The goal is to fill in the empty cells (represented by '.') with digits from 1 to 9 so that the rules of Sudoku are satisfied.
🔹 Key Points
- Each row must contain the digits 1-9 without repetition.
- Each column must contain the digits 1-9 without repetition.
- Each 3x3 subgrid must contain the digits 1-9 without repetition.
🛠 Solution Approach (Backtracking)
The most common approach to solving Sudoku is using backtracking:
- Find an empty cell.
- Try filling it with a digit from 1 to 9.
- Check if the digit is valid (doesn't violate Sudoku rules).
- If valid, recursively try to solve the rest of the puzzle.
- If the recursive call is successful, the puzzle is solved!
- If the recursive call is not successful, backtrack: reset the cell to empty and try a different digit.
- If all digits have been tried and none work, the puzzle has no solution (or the current path is incorrect).
#include
#include
using namespace std;
bool isSafe(vector>& grid, int row, int col, int num) {
// Check row
for (int x = 0; x < 9; x++)
if (grid[row][x] == num) return false;
// Check column
for (int x = 0; x < 9; x++)
if (grid[x][col] == num) return false;
// Check 3x3 box
int startRow = row - row % 3;
int startCol = col - col % 3;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
if (grid[i + startRow][j + startCol] == num) return false;
return true;
}
bool solveSudoku(vector>& grid) {
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
if (grid[row][col] == 0) { // Find an empty cell
for (int num = 1; num <= 9; num++) {
if (isSafe(grid, row, col, num)) {
grid[row][col] = num;
if (solveSudoku(grid)) return true; // Recursively solve
else grid[row][col] = 0; // Backtrack
}
}
return false; // No valid number found
}
}
}
return true; // Puzzle solved
}
int main() {
vector> grid = {
{5, 3, 0, 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, 0, 0, 0, 0, 0}
};
if (solveSudoku(grid)) {
cout << "Solution:\n";
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++)
cout << grid[i][j] << " ";
cout << endl;
}
} else {
cout << "No solution exists.\n";
}
return 0;
}
⏳ Time Complexity Analysis
The worst-case time complexity of the backtracking Sudoku solver is exponential. However, with proper constraints and pruning (checking `isSafe` efficiently), the practical runtime is often much faster.
🌍 Real-World Applications of Constraint Satisfaction
- 📅 Scheduling (timetables, appointments).
- 🏭 Resource allocation.
- 🤖 Artificial intelligence (planning).