본문 바로가기
[백준]

[BaekJoon/백준] 1941번 소문난 칠공주

by Hevton 2022. 6. 28.
반응형

 

이거 이틀이나 썼다.

 

원래 어제 풀었어야 했는데, 어제 두시간을 붙잡아도 풀지 못해서

오늘 다시 첨부터 짰다. 오늘도 오래 걸렸다.

 

 

짚고 넘어가야 할 하나가 있다.

 

이 문제에선 DFS(or BackTracking)이 두 종류가 사용되었다. 말 그대로 필요에 의해 두 가지로 활용되었다.

 

 

1. Arr[5][5] 행렬에서 7개를 뽑는 모든 경우의 수를 위한 DFS

5 x 5 행렬이 있을 때, 각 한번씩만 탐색해보는 경우의 수가 아니라, 7개를 뽑는 경우의 수. 조합이다.

매번 true / false를 토글해 가면서 뽑는다.
25개 중에서 7개를 뽑는 경우의 수.  대략 O(25C7)이 되겠다.

visit[check] = true;
DFS(i + 1)
visit[check] = false;

 

2. Arr[5][5] 행렬에서, 한 번씩 탐색해보는 완전 탐색 DFS

일단 뽑은 뒤에, 각각이 인접했는지를 확인할 때 사용된다. 대략 O(25)가 되겠다.

위 처럼 토글이 필요 없다. 그냥 한번 true 한 거 그대로 유지하며 나머지를 탐색한다.

 

 


 

 


#include <iostream>
#include <cstring>

using namespace std;


// 전체 맵
string MAP[5];

// 하 상 좌 우
int mx[4] = {1, -1, 0, 0};
int my[4] = {0, 0, -1, 1};


bool SELECT_CHECK[5][5]; // 뽑은 위치들을 나타내는 배열


bool ADJACENT_CHECK[5][5]; // 인접인지 체크할 때 사용하는 배열
int ADJACENT_COUNT; // 인접 체크가 7개가 되면 모두 체크한 것이므로 이 때, TOTAL_COUNT를 증가시킬 용도.

int TOTAL_COUNT; // 결과의 갯수

int S, Y; // S 수, Y 수


// ADJACENT와 SELECT의 DFS 활용 방법이 다르다는 것을 알아야 한다!



// DFS 지만, 시작에 CHECK = true 하도록 구현한 case
// => 전체에서, 최대 한번씩만 탐색하면 되는 완전탐색 case
// CHECK = true / CHECK = false를 토글해 줄 필요는 없는 경우지만, 시작에 하고 싶지 않으면 맨 첫 함수 호출 전에 따로 true 해주면 됨.
void ADJACENT(int x, int y) {
    
    
    int tx, ty;
    
    
    ADJACENT_CHECK[x][y] = true;
    
    if(++ADJACENT_COUNT == 7) {
        
        TOTAL_COUNT++;
            
        return;
    }
    
    
    
    for(int i = 0; i < 4; i++) {
        
        tx = x + mx[i];
        ty = y + my[i];
        
        
        if(tx < 0 || tx >= 5 || ty < 0 || ty >= 5)
            continue;
        
        if(SELECT_CHECK[tx][ty] && !ADJACENT_CHECK[tx][ty])
            ADJACENT(tx, ty);
        
    }
}


void EVALUATE(int x, int y) {
    
    S = Y = 0;
    
    
    for(int i = 0; i < 5; i++) {
        
        for(int j = 0; j < 5; j++) {
            
            if(SELECT_CHECK[i][j]) {
                
                if(MAP[i][j] == 'S')
                    S++;
                else if(MAP[i][j] == 'Y')
                    Y++;

            }
            
        }
    }
    
    if(S < 4) // 4개 이상이어야 함.
        return;
    
    // 시작 전 초기화.
    memset(ADJACENT_CHECK, 0, sizeof(ADJACENT_CHECK));
    ADJACENT_COUNT = 0;
    
    ADJACENT(x, y);
    
}


// 7 개를 뽑음. 다 뽑은 경우 유효한지 체크함.
// DFS 지만, 반복문 내부에서 CHECK = true 하고, CHECK = false 하는 토글이 필요한 case
// => 전체에서 N 개를 뽑는 모든 경우의 수가 필요한 case
void SELECT(int start, int K) {
    
    if(K == 8) { // 7개 뽑고 8번째 반복 시작이라면
        
        EVALUATE((start - 1) / 5, (start - 1) % 5); // 제일 마지막에 뽑았던 것 이용해서 평가 시작.
        
        return;
    }
    
    
    int tx, ty;
    
    for(int i = start; i <= 24; i++) {
        
        tx = i / 5;
        ty = i % 5;
        
        if(!SELECT_CHECK[tx][ty]) {
                    
            SELECT_CHECK[tx][ty] = true;
            
            SELECT(i + 1, K + 1);
            
            SELECT_CHECK[tx][ty] = false;

        }
    }
    
}


int main() {
    
    
    for(int i = 0; i < 5; i++) {
        cin >> MAP[i];
    }
    
    SELECT(0, 1);
    
    cout << TOTAL_COUNT << "\n";
    
}

 

 

젠장... 소요시간 셀 수도 없다 ㅋㅋ

반응형

'[백준]' 카테고리의 다른 글

[BaekJoon/백준] 14620번 꽃길  (0) 2022.06.29
[BaekJoon/백준] 14501번 퇴사  (0) 2022.06.28
[BaekJoon/백준] 1347번 미로 만들기  (0) 2022.06.27
[BaekJoon/백준] 2251번 물통  (0) 2022.06.26
[BaekJoon/백준] 14891번 톱니바퀴  (0) 2022.06.26