백준 4963

cw k·2022년 3월 3일
0

Algorithm

목록 보기
2/3
post-thumbnail

문제

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

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

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

입력

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

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

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

코드

package baekjoon.dfs;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Q4963 {

    static boolean[][] visited;
    static int[][] islands;
    static int W, H;
    static int[] dx = {-1, 1, 0, 0, -1, 1, -1, 1}; // ← → ↓ ↑ ↖ ︎↗ ︎↙ ︎↘︎
    static int[] dy = {0, 0, -1, 1, -1, -1, 1, 1}; // ← →  ↓ ↑ ↖ ︎↗ ︎↙ ︎↘︎

    public static void main(String[] args) throws Exception{
        StringBuilder sb = new StringBuilder();
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;

        while (true) {
            String wh = br.readLine();
            st = new StringTokenizer(wh, " ");

            W = Integer.parseInt(st.nextToken());
            H = Integer.parseInt(st.nextToken());

            if(W == 0 && H == 0) break; // 종료조건

            islands = new int[H][W];
            visited = new boolean[H][W];

            for (int i = 0; i < H; i++) {
                String s = br.readLine();
                st = new StringTokenizer(s, " ");
                for (int j = 0; j < W; j++) {
                    islands[i][j] = Integer.parseInt(st.nextToken());
                }
            }

            int result = 0;
            for (int i = 0; i < H; i++) {
                for (int j = 0; j < W; j++) {
                    if (islands[i][j] != 0 && !visited[i][j]) result += dfs(j, i); // 1
                }
            }
            sb.append(result).append("\n");
        }

        System.out.println(sb.toString());
    }

    private static int dfs(int x, int y) {
        visited[y][x] = true; // 2
        for (int i = 0; i < dx.length; i++) { // 3
            int nextX = x + dx[i];
            int nextY = y + dy[i];

            if(nextX < 0 || nextY < 0 || nextX >= W || nextY >= H // 배열범위
                    || islands[nextY][nextX] == 0 || visited[nextY][nextX]) continue; // 바다여부, 방문여부 // 4
            dfs(nextX, nextY); 
        }
        return 1; // 5
    }

}

해설

문제유형

탐색문제이다.
DFS, BFS 모두 이용 가능 하나 익숙하지 않은 DFS를 활용하여 풀었다.

변수설명

visited[][]: 방문 여부 저장 배열
islands[][]: 섬과 바다의 위치정보 (1: 섬 , 0: 바다)
W,H : 배열의 크기
dx[],dy[] : 탐색을 위한 x좌표, y좌표. 이번문제는 특이하게 대각선까지 방문가능한 지역으로 판단하기 때문에 대각선 좌표까지 포함되었다. dx[], dy[]배열의 각각의 인덱스를 묶어 화살표로 표현하면 ← → ↑ ↓ ↖ ︎↗ ︎↙ ︎↘︎ 와 같다.
result: 결과값 변수

풀이과정

앞서 DFS로 풀이한 11724번 노드 탐색 문제 풀이와는 다르게, 방문여부를 담는 배열 visited[][] 에 좌표(x,y)로 이루어진 2차원배열이 필요하다.

데이터 입력부 설명은 생략.

처리과정은 다음과 같다. (코드의 번호 주석 참조)

1 : 섬 && 방문하지 않음 조건일 경우 탐색에 들어간다.
2 : 탐색한 섬의 방문좌표에대해 방문여부를 true 로 변경한다.
3 : 현재노드를 기준으로 반목문을 돌며 앞서 선언한 dx[],dy[] 를 통해 ← → ↓ ↑ ↖ ︎↗ ︎↙ ︎↘︎ 좌표를 탐색하여 다음좌표의 값을 nextX, nextY 변수에 저장한다.
4 : nextX, nextY 값의 범위, 섬, 방문여부 유효성을 체크한다. 체크 후 방문 가능한 섬일 경우 재귀로 dfs를 호출한다.
5 : 탐색이 모두 끝나면 하나의 섬이라고 판단. 1을 리턴한다. 리턴값은 result 변수에 누적시킨다.

0개의 댓글