🎯 Mục tiêu bài học
- Áp dụng quay lui vào một bài thực tế phức tạp hơn tổ hợp/hoán vị.
- Hiểu cách kiểm tra điều kiện hợp lệ cục bộ trước khi đi sâu hơn.
- Đây là dạng bài rất hay gặp ở vòng loại HSG vì nó “đời thực nhưng giải thuật”.
📘 Mô tả bài toán
Sudoku chuẩn: bảng 9×9, điền số từ 1..9 sao cho: - Không lặp trong hàng - Không lặp trong cột - Không lặp trong mỗi ô vuông 3×3 Các ô chưa biết thường được đánh số 0.
💻 Thuật toán quay lui Sudoku
- Tìm ô còn 0.
- Thử đặt 1..9 vào ô đó nếu hợp lệ.
- Nếu hợp lệ: đệ quy giải phần còn lại.
- Nếu sau này bí → quay lui, thử giá trị khác.
Python
board = [list(map(int, input().split())) for _ in range(9)]
def ok(r, c, val):
# check row, col
for i in range(9):
if board[r][i] == val: return False
if board[i][c] == val: return False
# check 3x3 box
br, bc = (r//3)*3, (c//3)*3
for i in range(3):
for j in range(3):
if board[br+i][bc+j] == val:
return False
return True
def solve():
for r in range(9):
for c in range(9):
if board[r][c] == 0:
for v in range(1,10):
if ok(r,c,v):
board[r][c] = v
if solve():
return True
board[r][c] = 0
return False
return True
solve()
for row in board:
print(*row)
C++
#include <bits/stdc++.h>
using namespace std;
int board[9][9];
bool ok(int r, int c, int val){
for(int i=0;i<9;i++){
if(board[r][i]==val) return false;
if(board[i][c]==val) return false;
}
int br=(r/3)*3, bc=(c/3)*3;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
if(board[br+i][bc+j]==val)
return false;
return true;
}
bool solve(){
for(int r=0;r<9;r++){
for(int c=0;c<9;c++){
if(board[r][c]==0){
for(int v=1;v<=9;v++){
if(ok(r,c,v)){
board[r][c]=v;
if(solve()) return true;
board[r][c]=0;
}
}
return false;
}
}
}
return true;
}
int main(){
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
cin>>board[i][j];
solve();
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
cout<<board[i][j]<<" ";
}
cout<<"\n";
}
}
🧩 Bài tập luyện tập
- Đếm xem có bao nhiêu nghiệm Sudoku hợp lệ (không chỉ tìm 1 nghiệm).
- Viết chương trình in từng bước thử (log lại các lựa chọn).
- Nâng cấp để phát hiện input vô nghiệm (in ra “No solution”).
💡 Gợi ý: Đếm số nghiệm
# Ý tưởng:
# - thay vì return True khi tìm được nghiệm đầu tiên
# - bạn tăng biến đếm global và TIẾP TỤC quay lui để tìm nghiệm tiếp
# => dùng cho đề kiểu "Có bao nhiêu cách điền?"
💳 Quét mã ủng hộ tuỳ tâm nhé!