공부/백준

9663번: N-Queen(백준 C++)

상연 2020. 11. 9. 21:33

목차


    9663번: N-Queen 링크

    코드

    #include <iostream>
    using namespace std;
    
    int col[16] = {0,};
    int answer = 0;
    int n;
    
    bool check(int y){
        for(int i=1; i < y; i++){
            if(col[i] == col[y]) return false;
            if(y - i == abs(col[y] - col[i])) return false;
        }
        return true;
    }
    
    void solve(int x){
        if(x > n) answer += 1;
        else{
            for(int i=1; i<=n; i++){
                col[x] = i;
                if(check(x)) solve(x+1);
            }
        }
    }
    int main() {
        cin >> n;
        solve(1);
        cout << answer;
        return 0;
    }

    사견

    아 진짜 문제 풀면서 울고싶었다 오랜만에
    처음에 로직 자체는 맞게 짰는데, 연산자에서 실수 한 거 땜시 계속 머리 잡다가 겨우 풀었는데
    시간초과....

    시간초과 나게 푸는 방법!

    #include <iostream>
    using namespace std;
    
    int check[16][16];
    int answer = 0;
    
    void init(){
        for(int i=0; i<16; i++){
            for(int j=0; j<16; j++){
                check[i][j] = 0;
            }
        }
    }
    
    void pass_Q(int n, int y, int x, int b){
        for(int i=1; i<=n; i++){
            for(int j=1; j<=n; j++){
                if(i == y) check[i][j] += b;
                else if(j == x) check[i][j] += b;
                else if(abs(y - i) - abs(x - j) == 0) check[i][j] += b;
            }
        }
    }
    
    void solve(int n, int y, int x, int cnt){
        int i, j;
        i = y;
        j = x;
        if(cnt == n) answer += 1;
        else{
            for(int i = y; i<=n; i++){
                for(; j<=n; j++){
                    if(check[i][j] > 0) {
                        continue;
                    }
                    else{
                        pass_Q(n, i, j, 1);
                        solve(n, i, j, cnt+1);
                        pass_Q(n, i, j, -1);
                    }
                }
                j = 1;
            }
    
        }
    }
    int main() {
        init();
        int n;
        cin >> n;
        solve(n, 1, 1, 0);
        cout << answer;
        return 0;
    }

    느껴지십니까? 코드의 차이가...?
    우선 시간초과나게 풀었던 방법의 경우에는, 체스판...이라서 2차원 배열로 만들어놓고 풀었다.
    그 다음, Queen을 체스판에 두면, 이제 놓을 수 없는 위치에 1씩 증가시켜주었다.

    이렇게 하면 이제 배열의 값이 1 이상인 경우에는 Queen의 이동경로가 겹치는 구간이므로 Queen을 둘 수 없기 때문.
    Queen 두면서 Q이 지나갈 수 있는 경로에 1 증가하고...
    재귀하고... 재귀 끝나면 다시 두기 전으로 롤백해주고...

    이렇게 하면 일단 값은 나온다.

    하지만... 시간 복잡도가 엄청나버리게 되는것...

    시간초과에 너무 슬퍼서 그냥 해답을 찾아봤다.

    근데, 솔직히 안봤으면 못 풀었을거 같다... 이걸 어케 생각하지?

    찐 풀이

    하나의 열 또는 행에는 하나의 Queen 만이 올 수 있다.

    이것이 2차원 배열로 했던 체스판을 1차원 배열로 두는 핵심 Key 이다.

    위 그림을 보자.

    2차원 배열로 퀸의 위치를 나타낸다고 하면...
    bool chess[4][4];
    이러한 배열에서, Q의 위치는 chess[0][0] 그리고 chess[1][2] 이렇게 될 것이다.

    하지만 1차원 배열로 나타 낼 수 있다.
    어떻게?

    하나의 열 또는 행에는 하나의 Queen만이 올 수 있다...

    즉, chess[0][0] chess[0][1] chess[0][2] chess[0][3]
    행이 0인 4개의 위치중 어차피 Queen 하나 들어오면 나머지는 들어갈 수 없기때문에

    chess[0] = 0
    이렇게 index는 행 또는 열로 두고, 그 배열의 index 값에 Queen의 열 또는 행의 위치값을 넣어주면 된다는 것이다.

    이에 따라 1차원 배열로 바꿨을 시 위 그림에서 퀸의 위치는 아래와 같이 나타낼 수 있다.

    int chess[4];

    chess[0] = 0;
    chess[1] = 2;

    휴... 백트래킹을 써서 풀긴했었는데 이렇게 최적화에 막히니 가슴이 답답하고 통탄할 나름이다.......
    더 열심히 해야지....

    '공부 > 백준' 카테고리의 다른 글

    14888번: 연산자 끼워넣기(백준 C++)  (0) 2020.11.11
    2580번: 스도쿠(백준 C++)  (0) 2020.11.10
    1010번: 다리 놓기(백준 C++)  (0) 2020.11.08
    15651번: N과 M(3)(백준 C++)  (0) 2020.11.06
    15650번: N과 M(2)(백준 C++)  (0) 2020.11.05