읽기 전
- 해당 게시물은 작성자가 학습한 내용을 정리 및 요약 목적으로 작성되었으므로 오역 및 오개념이 있을 수 있습니다.
- 바로잡기 위한 의견을 제시해주시면 매우 감사하겠습니다.
N Queen Problem
N Queen Problem 이란 N*N 체스판이 주어졌을 때 N개의 queen을 서로 공격할 수 없는 위치에 배치할 수 있는가에 대한 문제이다.
위 그림처럼 4*4 체스판에 queen을 배치하면 어떠한 여왕도 서로의 공격 경로에 위치하지 않음을 알 수 있다, 그리고 이 배치를 배열로 표현하면 여왕이 있는 곳을 '1', 없는 곳을 '0'으로 표현할 수 있다.
{ 0, 1, 0, 0} { 0, 0, 0, 1} { 1, 0, 0, 0} { 0, 0, 1, 0}
Naive Algorithm
보드에 queen을 배치할 수 있는 경우를 모두 도출한 뒤 제약조건을 만족하는 경우에 출력한다.
시도하지 않은 경우의 수가 있다면
{
새로운 경우의 수를 생성하고
만약 queen들이 해당 경우의 수에서 공격할 수 없다면
{
경우의 수 출력
}
}
Backtracking Algorithm
먼저 좌측 첫 번째 column부터 queen들을 배치한다 그리고 queen을 배치할 때 이미 배치된 queen들과 충돌이 발생하는 지 검사한다. 현재 column에서 전투가 발생하지 않는 row가 존재한다면 해당 row 지점에 queen을 배치한다. 만약 충돌이 발생하지 않는 row를 찾을 수 없다면 backtrack 후 false를 return한다.
가장 좌측의 column에서 시작한다
만약 모든 queen들의 배치가 완료되면 true를 return한다.
현재 column에서의 모든 row에 대해 다음을 시도한다.
a) 만약 queen이 [row, column]에 성공적으로 위치할 수 있으면 체크 후 다음 column으로 넘어가서 재귀탐색한다.
b) 만약 [row, column]의 배치가 마지막 queen의 배치가 되면 true를 return하여 탐색을 종료한다.
c) 만약 배치했음에도 이후 단계에서 어떠한 해답이 존재하지 않는다면 backtrack 후 a)로 돌아가 다음 row에 대해 시도한다.
만약 모든 row에 대해 시도했음에도 해당사항이 없으면 false를 return하여 이전 단계에서 backtrack하도록 한다.
C코드
#include <stdio.h> #define N 4 void printSolution(int board[N][N]) { for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { printf(" %d", board[i][j]); } printf("\n"); } } bool isSafe(int board[N][N], int row, int col) { int i, j; for (i = 0; i < col; i++) // 해당 row에 대해 { if (board[row][i] == 1) // 다른 col에 queen이 있다면 { return false; // false 반환 } } for (i = row, j = col; i >= 0 && j >= 0; i--, j--) { if (board[i][j] == 1) { return false; // 좌측 상단 대각선에 queen 존재 검사 } } for (i = row, j = col; i < N && j >= 0; i++, j--) { if (board[i][j] == 1) { return false; // 좌측 하단 대각선에 queen 존재 검사 } } return true; } bool sovleNQUtil(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; // 해당 좌표에 queen 배치 if (sovleNQUtil(board, col + 1)) // 다음 col 탐색 { return true; // 문제 없으면 true 반환 } else { board[i][col] = 0; // backtracking } } } return false; // 이전 단계로 반환하여 backtrack trigger 작동 } bool solveNQ() { int board[N][N] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }; if (sovleNQUtil(board, 0) == false) { printf("There's no Solution!"); return false; } else { printSolution(board); return true; } } int main() { solveNQ(); return 0; }
Python 코드
def printSolution(board): for i in range(N): for j in range(N): print(board[i][j], end = " ") # 한칸씩 띄워서 출력 print() # 개행 def isSafe(board, row, col): for i in range(col): if board[row][i] == 1: return False # 같은 row에 queen이 있는지 검사 for i, j in zip(range(row, -1, -1), range(col, -1, -1)): if board[i][j] == 1: return False # 좌측 상단 대각선에 queen이 있는지 검사 for i, j in zip(range(row, N), range(col, -1, -1)): if board[i][j] == 1: return False # 좌측 하단 대각선에 queen이 있는지 검사 return True def solveNQUtil(board, col): if col >= N: return True # col이 끝까지 도달하면 탐색 종료 for i in range(N): if isSafe(board, i, col): # 유효한 위치라면 board[i][col] = 1 # 해당 좌표에 queen 배치 if solveNQUtil(board, col + 1) == 1: # 다음 col 탐색 진행 return True # 이후에 문제가 없으면 이전 단계에 통보 else: board[i][col] = 0 # 문제가 발생한다면 backtrack return False # 이전 단계에 통보하여 backtrack trigger 작동 def solveNQ(): board = [ [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0] ] if solveNQUtil(board, 0) == False: print("There's no Solution") else: printSolution(board) global N N = 4 solveNQ()
C++ 코드
c++ 코드는 C 코드와 문법을 비교했을 때 출력문을 제외하고는 없어서 주석을 생략하였다.
#include <bits/stdc++.h> using namespace std; #define N 4 void printSolution(int board[N][N]) { for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { cout << board[i][j] << " "; } cout << endl; } } bool isSafe(int board[N][N], int row, int col) { int i, j; for (i = col; i >= 0; i--) { if (board[row][i] == 1) { return false; } } for (i = row, j = col; i >= 0 && j >= 0; i--, j--) { if (board[i][j] == 1) { return false; } } for (i = row, j = col; i < N && j >= 0; i++, j--) { if (board[i][j] == 1) { return false; } } return true; } 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) == true) { board[i][col] = 1; if (solveNQUtil(board, col + 1) == true) { return true; } else { board[i][col] = 0; } } } return false; } bool solveNQ() { int board[N][N] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }; if (solveNQUtil(board, 0) == true) { printSolution(board); return true; } else { cout << "There's no Solution!" << endl; return false; } } int main() { solveNQ(); return 0; }
참고자료
'Algorithms > Geeks for Geeks' 카테고리의 다른 글
Backtracking | Rat in a Maze (0) | 2020.09.23 |
---|---|
Backtracking | The Knight’s tour problem (0) | 2020.09.23 |
Backtracking | Write a program to print all permutations of a given string (0) | 2020.09.18 |
Analysis of Algorithms | Performance of loops (A caching question) (0) | 2020.09.17 |
Analysis of Algorithms | Time Complexity of Loop with Powers (0) | 2020.09.17 |