in.add()

[17472] 다리 만들기 2 본문

Algorithm/BOJ

[17472] 다리 만들기 2

idan 2021. 9. 18. 23:32

문제 링크 : https://www.acmicpc.net/problem/17472

 

17472번: 다리 만들기 2

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

www.acmicpc.net

문제 해결 방법

  1. 섬에 번호를 매기기 위해 BFS.
  2. 섬마다 최소 길이로 놓을 수 있는 다리를 찾기 위해 DFS.
  3. 마지막으로 크루스칼로 MST를 구해줬다.

 

import java.util.*;

public class Main {
    static int N, M, islandCnt, answer, answerCnt;
    static int[][] map, dist;
    static int[] dx = {1, 0, -1, 0};
    static int[] dy = {0, 1, 0, -1};
    static int[] parent;
    static PriorityQueue<Node> q;
    static int INF = 100000;

    static class Node implements Comparable<Node> {
        int from;
        int to;
        int cost;

        public Node(int from, int to, int cost) {
            this.from = from;
            this.to = to;
            this.cost = cost;
        }

        public int compareTo(Node n) {
            return this.cost - n.cost;
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        N = sc.nextInt();
        M = sc.nextInt();
        map = new int[N][M];
        answer = 0;
        answerCnt = 1;

        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                map[i][j] = sc.nextInt();
            }
        }

        initMap();
        makeBridge();
        kruskal();
        if (answerCnt != islandCnt) {
            System.out.print("-1");
            return;
        }

        System.out.println(answer);
    }

    public static void makeBridge() {
        dist = new int[islandCnt + 1][islandCnt + 1];
        for (int i = 0; i <= islandCnt; i++) {
            for (int j = 0; j <= islandCnt; j++) {
                dist[i][j] = INF;
            }
        }

        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                if (map[i][j] != 0) {
                    for (int k = 0; k < 4; k++) {
                        int length = 0;
                        int nextX = i + dx[k];
                        int nextY = j + dy[k];
                        while (nextX >= 0 && nextX < N && nextY >= 0 && nextY < M) {
                            if (map[nextX][nextY] != 0) {
                                if (length > 1) {
                                    dist[map[i][j] - 1][map[nextX][nextY] - 1] = Math.min(length, dist[map[i][j] - 1][map[nextX][nextY] - 1]);
                                }
                                break;
                            }
                            length++;
                            nextX += dx[k];
                            nextY += dy[k];
                        }
                    }
                }
            }
        }
    }

    public static void kruskal() {
        parent = new int[islandCnt + 1];
        q = new PriorityQueue<>();

        for (int i = 1; i < dist.length; i++) {
            for (int j = 1; j < dist[i].length; j++) {
                if (dist[i][j] != INF) {
                    q.add(new Node(i, j, dist[i][j]));
                }
            }
        }

        for (int i = 0; i <= islandCnt; i++) {
            parent[i] = i;
        }

        while (!q.isEmpty()) {
            Node node = q.poll();
            if (find(node.from) != find(node.to)) {
                union(node.from, node.to);
                answer += node.cost;
                answerCnt++;
            }
        }
    }

    public static int find(int v) {
        if(parent[v] == v) return v;
        else return parent[v] = find(parent[v]);
    }

    public static void union(int from, int to) {
        int rootFrom = find(from);
        int rootTo = find(to);
        parent[rootTo] = rootFrom;
    }

    public static void initMap() {
        Queue<int[]> q = new LinkedList<>();
        boolean[][] visit = new boolean[N][M];
        int islandNum = 1;

        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                if (map[i][j] == 1 && !visit[i][j]) {
                    q.add(new int[]{i, j});
                    visit[i][j] = true;
                    islandNum++;
                }

                while (!q.isEmpty()) {
                    int[] cur = q.poll();
                    map[cur[0]][cur[1]] = islandNum;
                    for (int k = 0; k < 4; k++) {
                        int nextX = cur[0] + dx[k];
                        int nextY = cur[1] + dy[k];
                        if (nextX >= 0 && nextX < N && nextY >= 0 && nextY < M && map[nextX][nextY] == 1) {
                            q.add(new int[]{nextX, nextY});
                            visit[nextX][nextY] = true;
                        }
                    }
                }
            }
        }

        islandCnt = islandNum - 1;
    }
}

'Algorithm > BOJ' 카테고리의 다른 글

[16928] 뱀과 사다리 게임  (0) 2021.09.23
[2667] 단지 번호 붙이기  (0) 2021.09.22
[14003] 가장 긴 증가하는 부분 수열 5  (0) 2021.09.16
[14002] 가장 긴 증가하는 부분 수열 4  (0) 2021.09.16
[1149] RGB거리  (0) 2021.09.14
Comments