본문 바로가기

1p1d

[Day 4] 백준 9663 : N-queen

사실 3344번을 풀려고 했지만.. DFS로는 도저히 시간복잡도가 나오지 않는다. 그래서 다른 해법들을 찾아보니 케이스 by 케이스로 분류해서 비교해보는 문제였기 때문에 비교적 작은 값들로 시행하는 9663번을 선택하여 풀게 되었다.

해법 : DFS 

이긴 한데 사실상 시간 제한이 10초이기 때문에 가능한 해법이라고 볼 수 있다. 그만큼 DFS 시간복잡도가 매우 나쁘다. 특히 이 문제에서는 O(n!)의 시간복잡도.. n 최대가 15여서 가능한 풀이라고 볼 수 있다. 

 

어릴 때 이 문제를 처음 봤을 때에는 대각선 분류를 어떻게 해야하는지를 가지고 많은 시간을 고민했었던 것 같다. 그 학습의 결과인지 모르겠지만 대각선 분류는 행 번호(i)와 열 번호(j)를 이용하여 쉽게 할 수 있다.

 

slash 방향의 대각선은 i+j의 값이 일정하고 back slash 방향의 대각선은 i-j의 값이 일정함을 이용하여 해당 대각선을 사용했는지 안 사용했는지 쉽게 판별할 수 있다.

 

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;
int n;
int v1[200005];
int v2[200005];
int v3[200005];
int back_track[100005];
int flag;
int ans;
void dfs(int cnt) {
    if(cnt==n) {
        ans++;
        return;
    }
    int i;
    for(i=0;i<n;i++) {
        if(flag==1) return;
        if(v1[i]==1 || v2[i+cnt+1]==1 || v3[n+cnt-i]==1) continue;
        //back_track[cnt]=i;
        v1[i]=1;
        v2[i+cnt+1]=1;
        v3[n+cnt-i]=1;
        dfs(cnt+1);

        v1[i]=0;
        v2[i+cnt+1]=0;
        v3[n+cnt-i]=0;
    }
}
int main()
{
    freopen("input.txt","r",stdin);
    scanf("%d",&n);
    int i;
    for(i=0;i<n;i++) {
        if(flag==0) {
            v1[i]=1;
            v2[i+1]=1;
            v3[n-i]=1;
            back_track[0]=i;
            dfs(1);
            v1[i]=0;
            v2[i+1]=0;
            v3[n-i]=0;
        }
    }
    printf("%d\n",ans);
//for(i=0;i<n;i++) {
    //    printf("%d\n",back_track[i]+1);
    //}
    return 0;
}

 번외로 3344번 시도할 때 insert erase 등을 vector를 이용해서 시도해보았다. 효과는 미미했지만.. 

 

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>

using namespace std;
int n;
//int v1[200005];
int v2[200005];
int v3[200005];
int back_track[100005];
int flag;
vector <int> A;
void dfs(int cnt) {
    if(cnt==n || flag==1) {
        flag=1;
        return;
    }
    int i;

    for(i=0;i<A.size();i++) {
        vector <int> :: iterator it = A.begin()+i;
        int p = *it;
        //printf("%d ",A.size());
        if( v2[p+cnt+1]==1 || v3[n+cnt-p]==1 || flag==1) continue;
        back_track[cnt]=p;
        //v1[i]=1;
        A.erase(it);
        v2[p+cnt+1]=1;
        v3[n+cnt-p]=1;
        dfs(cnt+1);
        if(flag==1) return;

        A.insert(it,p);

        //v1[i]=0;
        v2[p+cnt+1]=0;
        v3[n+cnt-p]=0;

    }
}
int main()
{
    //freopen("input.txt","r",stdin);
    scanf("%d",&n);
    int i;
    for(i=0;i<n;i++) {
        A.push_back(i);
    }
    dfs(0);
    for(i=0;i<n;i++) {
        printf("%d\n",back_track[i]+1);
    }
    return 0;
}

'1p1d' 카테고리의 다른 글

[Day 4] 백준 7569 : 토마토  (0) 2021.01.24
[Day 3] 백준 2589 : 보물섬  (0) 2021.01.24
Schedule  (0) 2021.01.23
[Day 1] 백준 1753 : 최단경로  (0) 2021.01.22
[Day 1] 백준 1937 : 욕심쟁이 판다  (0) 2021.01.22