[BOJ] 4963 - 섬의 개수

황규빈·2021년 12월 27일
0

알고리즘

목록 보기
3/33

💎 문제


정사각형으로 이루어져 있는 섬과 바다 지도가 주어진다. 섬의 개수를 세는 프로그램을 작성하시오.

한 정사각형과 가로, 세로 또는 대각선으로 연결되어 있는 사각형은 걸어갈 수 있는 사각형이다.

두 정사각형이 같은 섬에 있으려면, 한 정사각형에서 다른 정사각형으로 걸어서 갈 수 있는 경로가 있어야 한다. 지도는 바다로 둘러싸여 있으며, 지도 밖으로 나갈 수 없다.


💎 입력

입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 테스트 케이스의 첫째 줄에는 지도의 너비 w와 높이 h가 주어진다. w와 h는 50보다 작거나 같은 양의 정수이다.

둘째 줄부터 h개 줄에는 지도가 주어진다. 1은 땅, 0은 바다이다.

입력의 마지막 줄에는 0이 두 개 주어진다.

💎 출력


각 테스트 케이스에 대해서, 섬의 개수를 출력한다.

💎 풀이 방법


저번 그래프 탐색 DFS 활용에 이어서 이번에는 BFS를 이용하여 풀었던 문제이다. BFS는 너비 우선 탐색을 활용한 그래프 탐색 방법으로 저번 DFS의 경우 계속해서 이어지는 정점들을 확인해 가면서 깊이 끝까지 도달하였을 때 백트래킹을 하였던 때에 반해 queue를 활용하여서 가장 가까운 정점들을 큐에 담아 그 들의 또 이어진 정점들을 push해가고 pop하는 과정을 활용하여 탐색을 하는 방식이다. 따라서 DFS보다 시간복잡도는 더 좋은 편이라고 할 수 있을 것 같다.

그래서 저번에는 DFS를 이용하여 풀었으니 이번 풀이는 BFS를 활용하였다. 먼저 나는 주로 pair을 이용하지 않는데 풀이하면서 방향에 대한 정보를 어떻게 이차원으로 queue에 전달해줄지라는 고민으로 결국 검색해보았는데 앞으로 pair을 이용해서 문제들을 풀 수 있는 것을 고려해보아야겠다!!

저번 DFS와 비슷한 방식으로 코드는 main부분과 BFS함수부분으로 구성되며 00이 입력되면 정지되는 while무한 루프를 구성하였다. 먼저 vector를 통해 지도의 너비와 높이에 따른 땅과 바다의 부분을 입력해주어 저장하였고, 이후에 탐색을 진행하였다.

for(int i = 0; i < h; i++){
	for(int j = 0; j < w; j++){
		if(!check[i][j] && v[i][j] == 1){
			BFS(i,j);
		}
	}
}

처음 시작은 왼쪽 대각선 끝에서 오른쪽 대각선 하단으로 탐색을 진행할 것이고 그래프 탐색이 완료가 되었는지와 (check[i][j] 가 false이면 탐색) 현재 부분이 땅인지 확인하여(v[i][j] == 1) BFS를 실행한다.

처음에 말했듯 BFS는 queue를 사용한다. queue에 현재 위치를 push한 뒤 그 위치 주변에 있는 정점들을 확인하여 이어진 땅을 다시 push하면서 확인 후에는 pop과 그 자리의 확인여부를 체크해주고 queue에 남은 정보들이 없다면 땅이 끊겼음을 의미하고 BFS가 한번 완료된 것을 의미한다. 이 때 이 지도에는 상하좌우 대각선 방향으로 4방향 더해서 총 8가지에 방향이 있는 데 이를 표현하기위해서 방향을 담아두는 x,y좌표의 배열을 선언해주고 이를 활용하여 현재 queue에 앞부분 front부분의 주변 위치들을 점검해주었다.

int dx[8] = {-1,-1,-1,0,1,1,1,0};
int dy[8] = {-1,0,1,1,1,0,-1,-1};
.
.
.
queue<pair<int, int>> q;
    q.push(make_pair(W, H));
    check[W][H] = true;
.
.
.
int tempX = x + dx[i];
int tempY = y + dy[i];

이렇게 tmepX와 tempY를 8가지 방향에 따라서 설정해주고 이 부분이 확인이 완료된 부분인지, 혹시 지도의 범위를 벗어나는지, 땅이 아닌지를 확인해주면서 점검을 완료시키고 이 점검을 통해 땅의 연장선상이면 queue에 좌표를 넣어주면서 점검이 완료되었다는 check값을 true로 바꾸어준다.

if(tempX < 0 || tempX >= h || tempY < 0 || tempY >= w) continue;
if(!check[tempX][tempY] && v[tempX][tempY] == 1){
	check[tempX][tempY] = true;
	q.push(make_pair(tempX, tempY));
}

이 작업이 완료되는 것이 BFS를 활용한 그래프 탐색의 끝이다!! 결국 탐색이 끝나면 queue에는 더이상 탐색할 수 있는 땅이 없다는 것이며 다음 위치의 정점으로 가서 새로운 BFS탐색을 진행할 것이다.

💎 전체 코드


#include <iostream>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
vector<vector<int>> v(51, vector<int>(51));
bool check[51][51];
int result = 0;
int dx[8] = {-1,-1,-1,0,1,1,1,0};
int dy[8] = {-1,0,1,1,1,0,-1,-1};
int w, h;

void BFS(int W, int H){
    
    queue<pair<int, int>> q;
    q.push(make_pair(W, H));
    check[W][H] = true;
    result++;

    while(!q.empty()){
        int x = q.front().first;
        int y = q.front().second;
        q.pop();

        for(int i = 0;i < 8;i++){
            int tempX = x + dx[i];
            int tempY = y + dy[i];
            if(tempX < 0 || tempX >= h || tempY < 0 || tempY >= w) continue;
            if(!check[tempX][tempY] && v[tempX][tempY] == 1){
                check[tempX][tempY] = true;
                q.push(make_pair(tempX, tempY));
            }
        }
    }
}

int main(int argc, const char * argv[]) {

    while(1){
        cin >> w >> h;

        if(w == 0 && h == 0)
            break;

        for(int i = 0;i < h;i++){
            for(int j = 0;j < w;j++){
                int temp;
                cin >> temp;
                v[i][j] = temp;
            }
        }

        for(int i = 0; i < h; i++){
            for(int j = 0; j < w; j++){
                if(!check[i][j] && v[i][j] == 1){
                    BFS(i,j);
                }
            }
        }
        cout << result << "\n";
        
        for(int i = 0;i < h;i++){
            for(int j = 0;j < w;j++){
                check[i][j] = false;
            }
        }

        for(int i = 0;i < h;i++){
            for(int j = 0;j < w;j++){
                v[i][j] = 0;
            }
        }
        result = 0;
    }

    return 0;
}

💎 고민


이번에 처음 pair을 이용해보면서 문제를 풀었는데 첫번째 부분과 두번째 부분을 지칭하면서 알고리즘을 작성할 수 있다는 것에 기억을 해야할 것 같다고 생각하였다.

그래프 탐색문제는 역시 저번 DFS에서 말했듯 첫 째로 어떤 식으로 어떤 방향으로 나아가면서 탐색을 할지 여부를 확인하고 둘 째로 그 탐색한 부분이 확인되었는지 해야하는지 체크해야하는 것을 염두하면서 풀도록 하자.

많이 안풀어보았다 보니 고민에 시간이 많이 걸린다 ㅠㅠ 그래프 탐색은 자주자주 풀어보고 알고리즘 감을 조금씩 찾아보자!!

화이팅~~

profile
안녕하세욤

0개의 댓글