[백준/BOJ] 2146 다리 만들기 - JAVA

2025. 6. 16. 21:29·알고리즘/문제풀이

 

 

 

 

[백준/BOJ] 2146 다리 만들기 - JAVA

문제

https://www.acmicpc.net/problem/2146

문제 분석

조건

N x N 크기의 지도에 1(육지)과 0(바다)이 주어진다. 여러 개의 섬이 있을 때, 한 섬에서 다른 섬으로 가는 가장 짧은 다리를 건설할 때 가장 짧은 다리의 길이를 구하라.

풀이방법

BFS를 2개 사용하는 방법으로 답을 구하였다. 처음 지도를 입력받고 모든 좌표를 탐색하며 육지일 경우 음수로 지도를 고쳐주는 BFS를 1번 사용했고, 육지에서 시작하는 BFS를 구하였다.

육지에서 시작하여 다리 길이를 구하는 BFS를 구현하기 위해 count 변수를 가진 Node 클래스를 정의하였고 우선순위큐를 이용하였다. 육지 좌표 하나에서 출발하는 bfs이기 때문에 출발 위치와 가장 가까운 섬의 위치가 반대쪽에 있을 경우 일반 큐를 사용하면 count가 0인 노드가 뒤에 나오므로 이미 다른 섬과 만났을 가능성이 있기 때문에 우선순위큐를 사용했다.

인터넷을 찾아보니 모든 섬의 가장자리를 전부 큐에 넣어두고 탐색을 시작하는 방법으로 구현하는 것을 봤다. 전체적인 BFS를 1번만 돌린다는 점에서 더 효율적이라는 생각이 들었다.

코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

class Node implements Comparable<Node> {
    int r, c;
    int count;

    public Node(int r, int c) {
        this.r = r;
        this.c = c;
    }

    public Node(int r, int c, int count) {
        this.r = r;
        this.c = c;
        this.count = count;
    }

    @Override
    public int compareTo(Node o) {
        return this.count - o.count;
    }
}

public class Main {
    static int N;
    static int[][] map;
    static int[][] dirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    static int answer = 10000;

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

        N = Integer.parseInt(br.readLine());
        map = new int[N][N];
        for (int r = 0; r < N; r++) {
            st = new StringTokenizer(br.readLine());
            for (int c = 0; c < N; c++) {
                map[r][c] = Integer.parseInt(st.nextToken());
            }
        }

        // 섬 수 카운팅 및 지도에 섬 표시
        int islandCount = 0;
        for (int r = 0; r < N; r++) {
            for (int c = 0; c < N; c++) {
                if (map[r][c] > 0) {
                    islandCount++;
                    islandCheck(r, c, (-1) * islandCount);
                }
            }
        }

        boolean[] islandStartCheck = new boolean[islandCount + 1];
        islandStartCheck[0] = true;
        for (int r = 0; r < N; r++) {
            for (int c = 0; c < N; c++) {
                if (!islandStartCheck[-1 * map[r][c]]) {
                    islandStartCheck[-1 * map[r][c]] = true;
                    bfs(r, c, map[r][c]);
                }
            }
        }
        System.out.println(answer);
    }

    /**
     * 시작 섬에서 출발하여 다른 섬 도착하는 거리 구하기
     *
     * @param r
     * @param c
     * @param startLand
     */
    private static void bfs(int r, int c, int startLand) {
        boolean[][] visited = new boolean[N][N];
        PriorityQueue<Node> que = new PriorityQueue<>();    // 다리 길이 짧은 순으로 탐색
        que.add(new Node(r, c));
        visited[r][c] = true;
        while (!que.isEmpty()) {
            Node now = que.poll();
            if (now.count > answer) {   // 다리가 정답보다 길어졌다면 탐색 불필요
                return;
            }
            for (int[] dir : dirs) {
                int nextR = now.r + dir[0];
                int nextC = now.c + dir[1];
                if (nextR < 0 || nextC < 0 || nextR >= N || nextC >= N || visited[nextR][nextC]) continue;
                if (map[nextR][nextC] == startLand) {   // 같은 섬
                    visited[nextR][nextC] = true;
                    que.add(new Node(nextR, nextC, 0));
                } else if (map[nextR][nextC] < 0) {   // 다른 섬
                    answer = Math.min(answer, now.count);
                    return;
                } else {    // 바다
                    visited[nextR][nextC] = true;
                    que.add(new Node(nextR, nextC, now.count + 1));
                }
            }
        }
    }

    /**
     * 같은 섬끼리 같은 번호로 지도 초기화 해주기. BFS
     *
     * @param r
     * @param c
     * @param islandNum
     */
    private static void islandCheck(int r, int c, int islandNum) {
        Deque<Node> que = new ArrayDeque<>();
        que.add(new Node(r, c));
        map[r][c] = islandNum;
        while (!que.isEmpty()) {
            Node now = que.poll();
            for (int[] dir : dirs) {
                int nextR = now.r + dir[0];
                int nextC = now.c + dir[1];
                if (nextR < 0 || nextC < 0 || nextR >= N || nextC >= N) continue;
                if (map[nextR][nextC] > 0) {
                    map[nextR][nextC] = islandNum;
                    que.add(new Node(nextR, nextC));
                }
            }
        }
    }
}
더보기

주절주절

뿌듯
무슨일이 있던걸까

나도 성장이란걸 했나 보다.

728x90
저작자표시 비영리 변경금지 (새창열림)
'알고리즘/문제풀이' 카테고리의 다른 글
  • [프로그래머스] 86053 금과 은 운반하기 - JAVA(파라메트릭 서치)
  • [백준/BOJ] 20057 마법사 상어와 토네이도 - JAVA
  • [백준/BOJ] 20056 마법사 상어와 파이어볼 - JAVA
  • [프로그래머스] 17678 [1차] 셔틀버스 - JAVA
LIRI
LIRI
  • LIRI
    기록
    LIRI
  • 전체
    오늘
    어제
    • 분류 전체보기 (72) N
      • 블로그 꾸미기 (0)
      • Spring (6)
      • React (3)
      • CS (0)
      • 알고리즘 (56) N
        • 개념 (2)
        • 문제풀이 (53) N
      • Java (1)
      • DB (1)
      • log (4)
        • SSAFY (3)
        • 궁금 (1)
  • 블로그 메뉴

    • 홈
    • 방명록
  • 공지사항

  • 인기 글

  • 태그

    LIS
    알고리즘 문제풀이
    백준
    lv3
    dp
    ssafy 합격 후기
    dfs
    그리디
    싸피
    도대체왜
    리액트
    불 끄기
    알고리즘
    비트마스킹
    BFS
    SSAFY 9기
    pccp모의고사
    Java
    프로그래머스
    springboot
    Springsecurity
    너비우선탐색
    LV2
    Security
    Spring
    최장증가부분수열
    JWT
    골드1
    BOJ
    SSAFY
  • 최근 댓글

  • 최근 글

  • 250x250
  • hELLO· Designed By정상우.v4.10.3
LIRI
[백준/BOJ] 2146 다리 만들기 - JAVA
상단으로

티스토리툴바