BOJ

백준 17472 - 다리 만들기 2

yanJuicy 2023. 3. 6. 16:33
반응형

문제

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

 

17472번: 다리 만들기 2

첫째 줄에 지도의 세로 크기 N과 가로 크기 M이 주어진다. 둘째 줄부터 N개의 줄에 지도의 정보가 주어진다. 각 줄은 M개의 수로 이루어져 있으며, 수는 0 또는 1이다. 0은 바다, 1은 땅을 의미한다.

www.acmicpc.net

 

풀이

지도에서 표시된 섬마다 다르게 숫자로 표시한다.

이를 위해 BFS로 탐색하면서 섬마다 값을 부여한다.

각 섬에서 다른 섬으로 연결할 수 있는 에지가 있는지 확인해서 에지 리스트를 만든다.

이를 위해 섬 마다 모든 점에서 상하좌우로 다리를 만들어본다.

만든 에지리스트로 크루스칼 알고리즘을 적용해 최소 신장 트리를 만든다.

 

코드

java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;

public class Main {

    private static int n, m;
    private static int[][] map;
    private static boolean[][] visit;
    private static int[] dx = {1, -1, 0, 0};
    private static int[] dy = {0, 0, 1, -1};
    private static ArrayList<int[]> pointList;
    private static ArrayList<ArrayList<int[]>> mapPointList;
    private static PriorityQueue<Node> edges;
    private static int result = 0;
    private static int edgeCount = 0;

    public static void main(String[] args) throws IOException {
        input();
        solve();
    }

    private static void solve() {
        int mapNum = 1;

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (map[i][j] == 1 && !visit[i][j]) {
                    bfs(i, j, mapNum++);
                    mapPointList.add(pointList);
                }
            }
        }

        for (ArrayList<int[]> islandPoints : mapPointList) {
            for (int[] point : islandPoints) {
                int curNum = map[point[0]][point[1]];
                for (int k = 0; k < 4; k++) {
                    int nx = point[0] + dx[k];
                    int ny = point[1] + dy[k];

                    int length = 0;
                    while (nx >= 0 && nx < n && ny >= 0 && ny < m) {
                        if (map[nx][ny] == curNum) {
                            break;
                        } else if (map[nx][ny] > 0) {
                            if (length >= 2) {
                                edges.add(new Node(curNum, map[nx][ny], length));
                            }
                            break;
                        }

                        nx += dx[k];
                        ny += dy[k];
                        length++;
                    }
                }
            }
        }

        kruskal(mapNum);
        if (edgeCount == mapNum - 2) {
            System.out.println(result);
        } else {
            System.out.println(-1);
        }
    }

    private static void kruskal(int mapNum) {
        int[] p = new int[mapNum];
        for (int i = 1; i < mapNum; i++) {
            p[i] = i;
        }

        while (!edges.isEmpty()) {
            Node cur = edges.poll();

            int s = cur.s;
            int e = cur.e;

            if (find(s, p) != find(e, p)) {
                union(s, e, p);
                result += cur.v;
                edgeCount++;
            }
        }
    }

    private static int find(int s, int[] p) {
        if (s == p[s]) {
            return s;
        }
        return p[s] = find(p[s], p);
    }

    private static void union(int s, int e, int[] p) {
        s = find(s, p);
        e = find(e, p);

        p[e] = s;
    }

    private static void bfs(int i, int j, int num) {
        pointList = new ArrayList<>();

        Queue<int[]> q = new LinkedList<>();

        visit[i][j] = true;
        q.offer(new int[] {i, j});

        while (!q.isEmpty()) {
            int[] cur = q.poll();
            map[cur[0]][cur[1]] = num;
            pointList.add(cur);

            for (int k = 0; k < 4; k++) {
                int nx = cur[0] + dx[k];
                int ny = cur[1] + dy[k];

                if (nx < 0 || nx >= n || ny < 0 || ny >= m) {
                    continue;
                }

                if (map[nx][ny] == 1 && !visit[nx][ny]) {
                    q.offer(new int[] {nx, ny});
                    visit[nx][ny] = true;
                }
            }
        }
    }

    private static void input() throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        String[] split = bufferedReader.readLine().split(" ");
        n = Integer.parseInt(split[0]);
        m = Integer.parseInt(split[1]);

        map = new int[n][m];
        visit = new boolean[n][m];
        for (int i = 0; i < n; i++) {
            split = bufferedReader.readLine().split(" ");
            for (int j = 0; j < m; j++) {
                map[i][j] = Integer.parseInt(split[j]);
            }
        }

        mapPointList = new ArrayList<>();
        edges = new PriorityQueue<>();
    }


    private static class Node implements Comparable<Node> {
        int s, e, v;

        public Node(int s, int e, int v) {
            this.s = s;
            this.e = e;
            this.v = v;
        }

        @Override
        public int compareTo(Node o) {
            return v - o.v;
        }
    }
}
반응형

'BOJ' 카테고리의 다른 글

BOJ 1158 - 요세푸스 문제  (1) 2024.01.28
백준 6416 - 트리인가?  (0) 2022.11.28
백준 1620 - 나는야 포켓몬 마스터 이다솜  (0) 2022.11.18
백준 2559 - 수열  (0) 2022.03.20
백준 2003 - 수들의 합 2  (0) 2022.03.17