ตัวอย่าง Backtracking
ปัญหา N Queen (ปัญหา classic)
https://leetcode.com/problems/n-queens/description/
เรามาเริ่มต้นรู้จัก Backtrack กับปัญหาสุด classic ที่ทุกคนที่เรียนรู้ Backtracking ต้องเรียนนั่นก็คือ N Queen
ปัญหา N-Queen เป็นปัญหา classic ในการจัดวาง Queen บนกระดานหมากรุกขนาด N*N โดยที่ Queen แต่ละตัวต้องไม่โจมตี Queen ตัวอื่น ซึ่งหมายความว่า Queen เหล่านั้นต้องไม่อยู่ในแนวเดียวกันทั้งแนวนอน แนวตั้ง และแนวทแยงมุม
เราจะใช้เทคนิค Backtracking ในการแก้ปัญหานี้ โดยจะค้นหาตำแหน่งที่เหมาะสมในการวาง Queen แต่ละตัว ถ้าไม่สามารถวาง Queen ได้ที่ตำแหน่งนั้น ก็จะย้อนกลับไปลองวาง Queen ที่ตำแหน่งก่อนหน้า และเราจะทำแบบนี้ไปเรื่อยๆจนกว่าจะเจอคำตอบสักคำตอบออกมาได้
class Solution {
public:
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> result;
vector<string> board(n, string(n, '.'));
solveNQueensUtil(result, board, 0, n);
return result;
}
private:
void solveNQueensUtil(vector<vector<string>> &result, vector<string> &board,
int row, int n) {
if (row == n) { // ถ้าวาง Queen ครบทุกแถวแล้ว เพิ่มผลลัพธ์เข้าไปใน vector result
result.push_back(board);
return;
}
for (int col = 0; col < n; col++) {
if (isSafe(board, row, col, n)) { // ตรวจสอบว่าสามารถวาง Queen ได้ที่ตำแหน่งนี้หรือไม่
board[row][col] = 'Q'; // วาง Queen ลงบนกระดาน
solveNQueensUtil(result, board, row + 1, n); // ค้นหาตำแหน่งสำหรับ Queen ตัวถัดไป
board[row][col] = '.'; // ถอด Queen ออกจากกระดาน (backtrack)
}
}
}
bool isSafe(vector<string> &board, int row, int col, int n) {
// ตรวจสอบแนวนอน
for (int i = 0; i < col; i++) {
if (board[row][i] == 'Q') {
return false;
}
}
// ตรวจสอบแนวตั้ง
for (int i = 0; i < row; i++) {
if (board[i][col] == 'Q') {
return false;
}
}
// ตรวจสอบแนวทแยงมุมซ้ายบน
for (int i = row, j = col; i >= 0 && j >= 0; i--, j--) {
if (board[i][j] == 'Q') {
return false;
}
}
// ตรวจสอบแนวทแยงมุมขวาบน
for (int i = row, j = col; i >= 0 && j < n; i--, j++) {
if (board[i][j] == 'Q') {
return false;
}
}
return true; // ถ้าไม่มีรากตัวใดโจมตีตำแหน่งนี้
}
};