[백준 9663] N-Queen(Java)

최민길(Gale)·2023년 1월 11일
1

알고리즘

목록 보기
7/172

문제 링크 : https://www.acmicpc.net/problem/9663

이 문제는 접근 방식을 다르게 하여 문제를 풀어야 합니다. 가장 직관적으로 문제를 풀 수 있는 방법은 2차원 배열을 만든 후 퀸을 하나하나 움직이면서 퀸이 존재하지 않는 경우 퀸을 추가하는 방식의 백트래킹으로 문제를 푸는 방법입니다. 하지만 저는 해당 방식으로 진행했을 때 결과값이 정상적으로 출력되지 않아 다른 방법을 생각해보았습니다.

우선 이 문제의 가장 키 포인트는 퀸의 위치를 체크하는 배열을 2차원 배열이 아닌 1차원 배열로 설정할 수 있다는 점입니다. 퀸의 특성 상 한 줄에 한 개만 놓을 수 있으므로 2차원 배열로 진행하더라도 결국 한 줄에 한 개의 값만 추가됩니다. 따라서 퀸의 가로 위치값 배열[퀸의 세로 위치값] = 퀸의 가로 위치값 과 같은 식으로 1차원 배열로 퀸의 위치를 표현할 수 있습니다.

퀸을 놓는 방법의 수를 구하는 로직은 다음과 같습니다.

  1. 첫 번째 줄부터 차례대로 탐색
  2. 현재 줄에서 퀸을 놓을 수 있는지 가로 방향으로 확인하기 위해 현재 줄의 가로값을 1씩 차례대로 증가
  3. 만약 현재 가로값이 퀸을 둘 수 있는 위치라면 다음 줄로 이동

이 때 퀸을 둘 수 있는 위치인지 판별할 수 있는 로직은 다음과 같습니다.

  1. 현재 줄 이전의 줄의 가로값과 세로값을 차례대로 탐색
  2. 만약 이전 줄과 가로값이 같다면 같은 세로선 상에 놓이게 되므로 퀸을 놓을 수 없음
  3. 만약 현재 줄의 세로값과 이전 줄의 세로값의 차와 현재 줄의 가로값과 이전 줄의 가로값의 차가 같다면 N X N 의 정사각형 체스판이기 때문에 같은 대각선상에 놓기게 되어 퀸을 놓을 수 없음
  4. 모든 케이스를 전부 확인했는데도 걸리는 부분이 없다면 퀸을 놓을 수 있음

따라서 위의 로직을 코드로 구현하면 아래와 같습니다.

import java.util.*;
import java.io.*;
import java.math.*;

public class Main {
    static int N;
    static int res = 0;
    static int[] column_num = new int[15];
    // 퀸의 특성 상 한 줄에 한 개만 놓을 수 있다.
    // 따라서 1차원 배열의 값으로 해당 row에 존재하는 퀸의 column 번호를 알 수 있다면
    // 굳이 2차원 배열을 만들어서 체크할 필요 없이 체크가 가능하다.

    static boolean canPutQueen(int curr_row_num){
        // 현재 줄 위의 있는 줄의 인덱스를 전부 비교
        for(int prev_row_num=0; prev_row_num<curr_row_num; prev_row_num++){
            // 이전 줄과 가로값이 같다면
            // 같은 세로선 상에 놓이게 되므로
            // 퀸을 놓을 수 없음
            if(column_num[prev_row_num] == column_num[curr_row_num]) return false;

            // 현재 줄과 이전 줄의 차와 가로값의 차가 같다면
            // N X N 의 정사각형 체스판이기 때문에
            // 같은 대각선상에 놓이게 되므로
            // 퀸을 놓을 수 없음
            if(Math.abs(prev_row_num - curr_row_num) == Math.abs(column_num[prev_row_num] - column_num[curr_row_num])) return false;
        }
        // 모든 케이스를 다 돌았는데도 걸리는 부분이 없다면
        // 퀸을 놓을 수 있음
        return true;
    }

    static void backtracking(int curr_row){
        // 현재 row가 끝까지 갔을 경우
        // 즉 퀸을 N개 만큼 놓았다면 리턴
        if(curr_row==N){
            res++;
            return;
        }

        for(int i=0;i<N;i++){
            // 퀸을 놓을 수 있는지 가로 방향으로 확인하기 위해
            // 현재 줄의 가로값을 1씩 증가시켜보기
            column_num[curr_row] = i;

            // 만약 현재 가로값이 퀸을 둘 수 있는 위치라면 다음 줄로 이동
            // 원래 백트래킹이라면 체크값을 재조정해야하지만
            // 현재 체크값이 반복문 안에서 매번 변경되기 때문에 재조정할 필요 없이 dfs 처럼 동작
            // 그렇지 않다면 백트래킹 실행하지 않기
            if(canPutQueen(curr_row)){
                backtracking(curr_row+1);
            }
        }
    }

    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());

        backtracking(0);
        System.out.println(res);
    }
}

profile
저는 상황에 맞는 최적의 솔루션을 깊고 정확한 개념의 이해를 통한 다양한 방식으로 해결해오면서 지난 3년 동안 신규 서비스를 20만 회원 서비스로 성장시킨 Software Developer 최민길입니다.

0개의 댓글

관련 채용 정보