백준 - 9663 - N-Queen

2021. 3. 8. 16:27Algorithm

 

www.acmicpc.net/problem/9663

 

9663번: N-Queen

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

www.acmicpc.net

import java.util.*;

/**
 * 백준 9663
 */
public class N_Queen {
    private static int M = -1;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        M = N;
        sc.close();
        //nqeen(N);
        nqeen2(N,new ArrayList<>());
        System.out.println(count);
    }

	//시간복잡도의 성능이 더 좋은 버전
    private static Set<Integer> columnSet = new HashSet<>();
    private static Set<Integer> plusSet = new HashSet<>();
    private static Set<Integer> minusSet = new HashSet<>();
    private static int count = 0;
    private static void nqeen(int N) {
        //종료
        if(N == 0) {
            count++;
            return;
        }

        //프로세스
        for(int i=1; i<=M; i++) {
            int plus = i + N;
            int minus = i - N;
            if(!columnSet.contains(i) && !plusSet.contains(plus) && !minusSet.contains(minus)) {
                minusSet.add(minus);
                plusSet.add(plus);
                columnSet.add(i);
                nqeen(N-1);
                columnSet.remove(i);
                plusSet.remove(plus);
                minusSet.remove(minus);
            }
        }
    }

	//공간복잡도의 성능이 더 좋은 버전
    private static void nqeen2(int N, List<Integer> prefix) {
        //종료
        if(N == 0) {
            count++;
            //System.out.println(prefix);
            return;
        }

        //프로세스
        for(int i=1; i<=M; i++) {
            int plus = i + N;
            int minus = i - N;
            //유효성 검사
            boolean isAble = true;
            int row = M;
            for(int j=0; j<prefix.size(); j++) {
                int col = prefix.get(j);
                if(plus == row+col || minus == col-row || col == i) {
                    isAble = false;
                    break;
                }
                row--;
            }

            if(isAble) {
                prefix.add(i);
                nqeen2(N-1, prefix);
                prefix.remove(prefix.size()-1);
            }
        }
    }
}

 

문제해석

N*N 보드가 주어졌을때 N개의 퀸을 보드 위에 놓는 경우 중 서로 공격할 수 있는(같은 행, 같은 열, 같은 대각선에 일치) 경우를 제거한 모든 경우의 수를 출력하는 문제.

 

알고리즘

백트래킹, 순열

  • 문제의 핵심은 만약 N이 4일 경우 처음에 퀸을 놓을 수 있는 경우는 16가지가 된다. 근데 생각해보면 퀸은 서로 같은 행에 놓을 수 없음으로 한 행만 따로 분리하여 생각하면 4가지로 줄일 수 있다.
  • 이렇게 생각했을때 모든 조합에서 각 행에 퀸을 놓을 수 있는 위치만 생각해주면 된다.
  • 퀸을 놓을 수 있는지 판단하는 시간복잡도는 O(N)이 걸린다. N개의 퀸의 위치와 현재 놓으려고 하는 퀸을 비교해서 같은 행, 같은 열, 같은 대각선에 위치하는지 검사해주면 되기 때문이다.
  • 하지만 같은 행인 경우는 배제하고 진행하기 때문에 따로 검사하지 않아도 되고 대각선인 경우는 위치의 합과 차이가 같은 대각선이면 같은 성질을 이용하여 판단할 수 있다.
  • 하지만 이 로직을 HashSet을 이용하면 O(1)로 줄일 수 있다. 하지만 백준에서는 메모리 초과에 걸리게 되므로 순회하여 O(N)의 시간복잡도를 가져가야한다.

'Algorithm' 카테고리의 다른 글

백준 - 15652 - N과 M(4)  (0) 2021.03.09
백준 - 15651 - N과 M(3)  (0) 2021.03.09
백준 - 15650 - N과 M(2)  (0) 2021.03.08
백준 - 15649 - N과 M(1)  (0) 2021.03.08
백준 - 10451 - 순열 사이클  (0) 2021.03.05