궤도

[백준] 2667번 : 단지번호붙이기 본문

💻 현생/⛓ 알고리즘

[백준] 2667번 : 단지번호붙이기

영이오 2021. 4. 7. 20:29

문제

 


풀이

 

문제 이름에 왜 띄어쓰기가 없을까? 그냥 의문점이다.

 

배열을 돌면서 1로 표시된 지점을 찾으면 그 지점을 root로 하는 bfs 또는 dfs로 연결된 모든 1을 찾는다.

bfs, dfs에서 빠져나왔다는 건 더이상 해당 root와 이어진 1이 없다는 뜻이니까 다시 새로운 1이 나올때까지 배열을 돌면 되겠다.

난 그냥 편하게 재귀함수 돌리려고 dfs로 했다.

 

그나저나 이런 문제를 풀땐 상하좌우로 이동하면서 풀어야 하는데..

아무생각없이 상하좌우로 이동하다간 5x5배열에서 [-1][0]을 참조하거나 [6][2]를 참조하게 될 수도 있다.

이걸 해결하는 방법은 여러가지가 있지만

 

난 이렇게 상하좌우 테두리를 둘러주는 방법을 선호한다.

위아래 2줄씩 더 생긴다고 큰 일이 일어나진 않을테니까...


소스코드

 

#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <utility>

using namespace std;

//범위 초과 때문에 상하좌우 한줄씩 추가
int matrix[27][27], N, local_cnt;
vector<int> cluster; //각 단지내 집의 수
pair<int, int> dir[4] = {{-1, 0},  //상
                         {1,  0},  //하
                         {0,  -1}, //좌
                         {0,  1}}; //우

void dfs(pair<int, int> pos) { //같은 단지에 속한 집을 찾는 dfs
    for (int i = 0; i < 4; i++) { //현위치의 상하좌우 좌표를 row, col에 저장
        int row = pos.first + dir[i].first;
        int col = pos.second + dir[i].second;
        if (matrix[row][col] == 1) { //방문한 적 없는 집(leaf)
            local_cnt++; //해당 단지의 집의 수 증가
            matrix[row][col] = 0; //방문 체크
            pair<int, int> next_pos = {row, col};
            dfs(next_pos); //재귀 호출
        }
    }
}

int findHouse() {
    int cnt = 0; //총 단지수

    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= N; j++) {
            if (matrix[i][j] == 1) { //방문한 적 없는 집(root)
                cnt++; //총 단지 수 증가
                local_cnt = 1;
                matrix[i][j] = 0;
                pair<int, int> start = {i, j};
                dfs(start); //연결된 모든 집을 찾음
                cluster.push_back(local_cnt); //단지내 집의 수를 저장
            }
        }
    }
    return cnt;
}

int main() {
    string tmp;

    cin >> N;
    for (int i = 1; i <= N; i++) {
        cin >> tmp;
        for (int j = 1; j <= N; j++)
            matrix[i][j] = tmp[j - 1] - '0';
    }
    cout << findHouse() << '\n'; //총 단지수 출력
    sort(cluster.begin(), cluster.end()); //정렬
    for (int i = 0; i < cluster.size(); i++) //단지별 집의 수 출력
        cout << cluster[i] << '\n';
}

전체 소스코드다.

 

//범위 초과 때문에 상하좌우 한줄씩 추가
int matrix[27][27], N, local_cnt;
vector<int> cluster; //각 단지내 집의 수
pair<int, int> dir[4] = {{-1, 0},  //상
                         {1,  0},  //하
                         {0,  -1}, //좌
                         {0,  1}}; //우

최대 입력이 25x25라고 했으니 27x27 크기의 2차원 배열을 선언한다.

전역변수 local_cnt는 dfs를 도는 단지내 집의 수를 저장할 것이다. 그 결과는 cluster에 저장할 것이다.

그리고 상하좌우를 좀 편하게 접근하기 위해 페어 배열 dir를 만들었다.

 

    string tmp;

    cin >> N;
    for (int i = 1; i <= N; i++) {
        cin >> tmp;
        for (int j = 1; j <= N; j++)
            matrix[i][j] = tmp[j - 1] - '0';
    }

도대체 왜 입력을 띄어쓰기 없이 넣는지 모르겠지만 입력을 받고...

 

int findHouse() {
    int cnt = 0; //총 단지수

    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= N; j++) {
            if (matrix[i][j] == 1) { //방문한 적 없는 집(root)
                cnt++; //총 단지 수 증가
                local_cnt = 1;
                matrix[i][j] = 0;
                pair<int, int> start = {i, j};
                dfs(start); //연결된 모든 집을 찾음
                cluster.push_back(local_cnt); //단지내 집의 수를 저장
            }
        }
    }
    return cnt;
}

총 단지 수를 리턴할 findHouse 함수다.

반복문을 돌다가 집을 발견하면 총 단지의 수를 늘려주고 local_cnt를 1로 초기화 한다.(root 집이 있으니까)

matrix[i][j]를 0으로 만들어 방문 표시를 한다. visited를 true로 체크하던 것과 같다.

그리고 이 root 집에 대한 dfs를 호출한다. dfs 후 local_cnt가 바뀌어 있을 것이다. 이를 cluster에 넣어준다.

 

void dfs(pair<int, int> pos) { //같은 단지에 속한 집을 찾는 dfs
    for (int i = 0; i < 4; i++) { //현위치의 상하좌우 좌표를 row, col에 저장
        int row = pos.first + dir[i].first;
        int col = pos.second + dir[i].second;
        if (matrix[row][col] == 1) { //방문한 적 없는 집(leaf)
            local_cnt++; //해당 단지의 집의 수 증가
            matrix[row][col] = 0; //방문 체크
            pair<int, int> next_pos = {row, col};
            dfs(next_pos); //재귀 호출
        }
    }
}

재귀함수로 구현한 dfs다. 상하좌우 좌표를 확인하며 집이 있는지 본다.

집을 발견한 뒤 코드 진행은 findHouse에서 집을 발견했을 때와 매우 유사하나,

총 단지 수가 아닌 단지내 집의 수를 늘려준다는 것이 다르다.

 

    cout << findHouse() << '\n'; //총 단지수 출력
    sort(cluster.begin(), cluster.end()); //정렬
    for (int i = 0; i < cluster.size(); i++) //단지별 집의 수 출력
        cout << cluster[i] << '\n';

정렬하라고 헀으니까 정렬한 뒤 출력한다.

Comments