JUINTINATION

백준 9663번: N-Queen 본문

백준 알고리즘/백트래킹

백준 9663번: N-Queen

DEOKJAE KWON 2022. 6. 28. 20:52
반응형

문제

https://www.acmicpc.net/problem/9663

 

9663번: N-Queen

N-Queen 문제는 크기가 N × N인 체스판 위에 퀸 N개를 서로 공격할 수 없게 놓는 문제이다. N이 주어졌을 때, 퀸을 놓는 방법의 수를 구하는 프로그램을 작성하시오.

www.acmicpc.net

 


풀이

N × N인 체스판 위에 퀸 N개를 서로 공격할 수 없게 놓는 경우의 수를 구하는 문제입니다.

체스 규칙에 따르면 퀸은 상하좌우, 대각선 방향으로 기물이 없는 칸에 한해서 칸수의 제한 없이 움직일 수 있는 말입니다. 따라서 퀸은 xy 좌표로 생각했을 때 각 x 좌표에 1개씩, 각 y 좌표에 1개씩 있어야 하고 대각선상에서 겹치면 안 됩니다.


코드

C언어

정수 배열 x와 nQueen 함수의 매개변수 y는 각각 n x n 크기의 체스판에서의 x 좌표y 좌표를 의미합니다. 정수 배열 board퀸의 위치(board[y 좌표] = x 좌표)를 기록하는 역할을 합니다.

함수 안의 for문에서 xy 좌표(i, y)로 표현하고 x 좌표가 i인 곳에 퀸이 위치하고 있지 않다면(x[i] != 1) board[y] = i로 현재 y값에 대한 퀸의 위치를, x[i] = 1으로 x 좌표가 i인 곳에 퀸을 1개 두었다는 것을 기록합니다.

이후에 대각선상에 퀸이 있는지 확인하기 위해 j를 포함한 for문으로 2개의 퀸의 x 좌표의 차이와 y 좌표의 차이가 같은지 확인합니다. 이때 j가 0이면 board[y] - board[y - 0] = 0이기 때문에 항상 if문을 만족하기 때문에 j는 1부터 시작합니다.

위의 모든 조건을 만족하면 체스판에서 다음 y 값에 대해 검사하기 위해 재귀적으로 nQueen(y + 1)을 실행하고 모든 y 값에 퀸을 1개씩 놓았다면(y == n) 이 문제의 조건을 만족하는 것이므로 cnt에 1을 더해줍니다.

y 좌표가 0일때부터 n - 1일 때까지 확인하기 위해 main 함수에서 nQueen(0)을 실행한 뒤에 cnt를 출력합니다.

#include <stdio.h>
#include <math.h>
int n, board[15], x[15] = { 0 }, cnt = 0;
void nQueen(int y) {
	if (y == n) {
		cnt++;
		return;
	}
	for (int i = 0; i < n; i++) {
		if (x[i] != 1) {
			board[y] = i;
			x[i] = 1;
			int tst = 1;
			for (int j = 1; j <= y; j++) {
				if (abs(board[y] - board[y - j]) == j) {
					tst = 0;
					break;
				}
			}
			if (tst) nQueen(y + 1);
			x[i] = 0;
		}
	}
}
main() {
	scanf("%d", &n);
	nQueen(0);
	printf("%d", cnt);
}

자바

사실 이 문제는 백트래킹 카테고리에 위치해있긴 하지만 dfs(깊이우선탐색)을 이용하여 푸는 문제라고도 할 수 있습니다. 이를 표현하기 위해 위의 C언어 코드에서 nQueen 함수 이름을 dfs로, 함수의 매개변수 y를 dpth로, 정수 배열 x를 bool 배열 visited로 바꿔보았습니다. 풀이는 위와 같습니다.

import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main {

    static int n, cnt = 0;
    static int[] arr;
    static boolean[] visited;

    public static void dfs(int dpth) {
        if (dpth == n) {
            cnt++;
            return;
        }
        for (int i = 0; i < n; i++) {
            if (!visited[i]) {
                arr[dpth] = i;
                visited[i] = true;
                boolean tst = true;
                for (int j = 1; j <= dpth; j++) {
                    if (Math.abs(arr[dpth] - arr[dpth - j]) == j) {
                        tst = false;
                        break;
                    }
                }
                if (tst) {
                    dfs(dpth + 1);
                }
                visited[i] = false;
            }
        }
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        n = Integer.parseInt(br.readLine());
        arr = new int[n];
        visited = new boolean[n];
        dfs(0);
        System.out.println(cnt);
    }
}

 


결론

처음에 이 문제를 풀 때는 dfs이라는 알고리즘을 알고있지 않은 상태였습니다. 추후에 자바를 공부하기 시작하면서 dfs에 대해 알게 되었는데 이 알고리즘을 모르는 상태에서도 비슷한 방식으로 풀었다는 사실에 놀랐던 기억이 있습니다. 앞으로도 알고리즘을 모른다고 문제를 포기하는 것이 아니라 끝까지 노력하여 풀 수 있는 사람이 되기 위해 노력해야겠습니다.

728x90

'백준 알고리즘 > 백트래킹' 카테고리의 다른 글

백준 16938번: 캠프 준비  (0) 2022.07.12
백준 16936번: 나3곱2  (0) 2022.07.07
백준 16945번: 매직 스퀘어로 변경하기  (0) 2022.07.02
백준 4574번: 스도미노쿠  (0) 2022.06.30
백준 2580번: 스도쿠  (3) 2022.06.29
Comments