백준 9663 - N-Queens

백트래킹 | 2026.03.16


🧩 문제 이해

N×N 체스판에 퀸을 N개 놓는데, 퀸끼리 서로 공격할 수 없게 배치하는 경우의 수를 구하는 문제다.

퀸은 상하좌우 + 대각선 방향으로 거리 제한 없이 이동하기 때문에, 같은 행 / 열 / 대각선에 두 퀸이 있으면 안 된다.


💡 핵심 관찰

  • N개의 퀸을 N개의 행에 놓아야 하므로, 각 행에 퀸이 정확히 1개씩 있어야 한다.
  • 즉, 행을 하나씩 내려가며 어느 열에 퀸을 놓을지 결정하면 된다 → DFS + 백트래킹

🔄 백트래킹이란?

가능성이 없는 경우를 조기에 차단(가지치기)하면서 DFS로 탐색하는 방식이다.

일반 DFS는 끝까지 가보고 틀리면 돌아오지만, 백트래킹은 중간에 "이건 답이 될 수 없다"고 판단되면 즉시 되돌아온다.


📐 충돌 조건 수학적으로 표현하기

두 퀸의 좌표가 (r1, c1), (r2, c2)일 때:

같은 열     : c1 == c2
↘ 대각선   : r1 - c1 == r2 - c2
↗ 대각선   : r1 + c1 == r2 + c2

이걸 bool 배열 3개로 관리하면 충돌 체크를 O(1) 에 할 수 있다:

col[c]        // 열 체크
diag1[r+c]    // ↗ 대각선 (r+c 값이 같으면 같은 대각선)
diag2[r-c+N]  // ↘ 대각선 (r-c 값이 같으면 같은 대각선, 음수 보정 +N)

배열 크기 계산

| 배열 | 범위 | 크기 | |------|------|------| | col | 0 ~ N-1 | 15 | | diag1[r+c] | 0 ~ 28 | 29 | | diag2[r-c+N] | 0 ~ 28 | 29 |


✅ 최종 코드

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

int N, cnt = 0;
vector<bool> col(15, false);
vector<bool> diag1(29, false);
vector<bool> diag2(29, false);

void track(int r) {
    if (r == N) {
        cnt++;
        return;
    }
    for (int i = 0; i < N; i++) {
        if (!col[i] && !diag1[r+i] && !diag2[r-i+N]) {
            col[i] = true;
            diag1[r+i] = true;
            diag2[r-i+N] = true;
            track(r + 1);
            col[i] = false;
            diag1[r+i] = false;
            diag2[r-i+N] = false;
        }
    }
}

int main() {
    cin >> N;
    track(0);
    cout << cnt;
}

🗣️ 회고

  • 처음엔 퀸의 이동범위를 킹이랑 헷갈렸다. 퀸은 방향만 같으면 거리 무제한.
  • 대각선 조건을 NxN visited로 구현하려다가, 배열 3개 + O(1) 체크 방식이 훨씬 깔끔하다는 걸 깨달았다.
  • diag2[r-c+N]에서 r-c가 음수가 될 수 있으니 +N으로 보정하는 게 핵심 디테일이었다.
  • 전역 bool 배열을 false로 명시 초기화해야 한다는 것도 챙겨야 할 부분.