Iriton's log

[Algorithm/Java] 깊이 우선 탐색(DFS) - 4963번: 섬의 개수 본문

Problem Solving/C,C++

[Algorithm/Java] 깊이 우선 탐색(DFS) - 4963번: 섬의 개수

Iriton 2023. 9. 26. 11:03

문제


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

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

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

 

입력


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

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

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

 

출력


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

 

풀이


해당 문제는 격자 형태의 지도에서 땅과 바다의 정보가 주어진다. 

주어진 격자에서 서로 다른 섬의 개수를 구하는 문제이다.

이 문제는 탐색 알고리즘을 이용해야 한다.

BFS보다는 DFS을 이용해 보자.

 

DFS(Depth First Search)

그래프나 트리와 같은 자료구조에서 깊은 부분을 우선적으로 탐색하는 알고리즘

스택이나 재귀 호출을 통해 구현할 수 있다.

시작 정점에서부터 시작하여 한 정점에서 가능한 한 깊이 들어가면서 탐색하는 것이다.

더이상 갈 곳이 없으면 되돌아가서 다른 경로로 탐색한다.

이 과정을 반복하여 모든 정점을 방문하게 된다.

 

1. 시작 정점을 선택하여 스택에 넣거나, 방문 처리한다.(재방문 방지)

2. 선택한 정점과 인접한 정점 중 방문하지 않은 정점을 선택하여 이동한다.

(이때 재귀호출을 사용할 수 있다. 마치 해당 정점이 시작 정점인 것처럼)

3. 선택한 정점으로 이동하여 방문하고 1번처럼 스택에 넣거나, 방문 처리한다.

4. 더이상 갈 곳이 없다면 이전 정점으로 돌아가서 다른 경로로 탐색을 진행한다.

(재귀호출 함수를 이용했다면 함수를 종료시키고 호출 위치로 돌아가는 걸 의미한다.)

5. 모든 정점을 방문할 때까지 반복한다.

 

 

코드


import java.util.Scanner;

public class Main {
    static int[] dx = {-1, 1, 0, 0, -1, -1, 1, 1}; // 상하좌우 및 대각선 방향
    static int[] dy = {0, 0, -1, 1, -1, 1, -1, 1};
    
    static void dfs(int[][] grid, boolean[][] visited, int x, int y, int w, int h) {
        // 범위를 벗어나거나 이미 방문한 지점이거나 바다인 경우 종료
        if (x < 0 || y < 0 || x >= h || y >= w || visited[x][y] || grid[x][y] == 0)
            return;
        
        visited[x][y] = true; // 현재 지점을 방문 처리
        
        // 인접한 지점을 탐색
        for (int i = 0; i < 8; i++) {
            int nx = x + dx[i];
            int ny = y + dy[i];
            dfs(grid, visited, nx, ny, w, h);
        }
    }
    
    static int countIslands(int[][] grid, int w, int h) {
        boolean[][] visited = new boolean[h][w];
        int islandCount = 0;
        
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                if (grid[i][j] == 1 && !visited[i][j]) {
                    // 새로운 섬을 발견하면 DFS를 수행하여 섬의 개수 증가
                    dfs(grid, visited, i, j, w, h);
                    islandCount++;
                }
            }
        }
        
        return islandCount;
    }
    
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        while (true) {
            int w = scanner.nextInt();
            int h = scanner.nextInt();
            
            if (w == 0 && h == 0)
                break;
            
            int[][] grid = new int[h][w];
            
            // 격자 정보 입력
            for (int i = 0; i < h; i++) {
                for (int j = 0; j < w; j++) {
                    grid[i][j] = scanner.nextInt();
                }
            }
            
            int result = countIslands(grid, w, h);
            System.out.println(result);
        }
    }
}

'Problem Solving > C,C++' 카테고리의 다른 글

[C/BOJ] 1978번: 소수 찾기  (0) 2023.10.11
[C/BOJ] 14938번: 서강그라운드  (0) 2023.10.11
[C++/BOJ] 2293번: 동전 1  (0) 2023.05.31
[C++/BOJ] 2212번: 센서  (0) 2023.05.31
[C] 9095번: 1, 2, 3 더하기  (0) 2023.05.17
Comments