[프로그래머스] 섬 연결하기 (Java) (Python)

박지훈·2021년 2월 26일
0

문제

링크

복습 요망!



나의 풀이

1. 비용이 최소인 것들 부터 탐색 시작

2. 선이 n-1개가 되면 탐색 종료

즉, 비용이 최소인 것들만 n-1개 될 때까지 합하자. 라는 풀이 방법을 세웠다. 왜냐하면 문제에서

  • 같은 연결은 두 번 주어지지 않습니다. 또한 순서가 바뀌더라도 같은 연결로 봅니다. 즉 0과 1 사이를 연결하는 비용이 주어졌을 때, 1과 0의 비용이 주어지지 않습니다.
  • 모든 섬 사이의 다리 건설 비용이 주어지지 않습니다. 이 경우, 두 섬 사이의 건설이 불가능한 것으로 봅니다.

이러한 조건이 주어졌기 때문에 내 풀이가 정답인 줄 알았으나 아니였다...

정답 풀이

다른 사람의 풀이는 살펴보니 크루스칼 알고리즘을 이용해야했다. 이 문제는 MST(Minimum Spanning Tree)의 기본 개념을 활용하는 문제이다. MST 문제를 해결하기 위해서는 크루스칼 알고리즘을 이용하자.

  • MST --> 크루스칼 알고리즘 임을 기억하자!

  1. 비용이 최소인 것들을 오름차순으로 정렬

  2. 비용이 최소인 것 들부터 간선을 연결한다. 이 때 사이클이 형성되지 않도록 연결해야한다!
    union-find 알고리즘이 이용된다. 꼭 기억하자!



코드

// Java
import java.util.*;

class Edge implements Comparable<Edge> {
    int start, end, cost;

    public Edge(int start, int end, int cost) {
        this.start = start;
        this.end = end;
        this.cost = cost;
    }

    @Override
    public int compareTo(Edge o) {
        return this.cost - o.cost;
    }
}

class Solution {
    
    static int[] parent;
    static PriorityQueue<Edge> pq;
    
    public int solution(int n, int[][] costs) {
        int answer = 0;
        parent = new int[n];
        pq = new PriorityQueue<Edge>();

        // 정점들의 부모 설정
        for (int i = 0; i < n; i++)
            parent[i] = i;

        // 비용 적은 순서부터 우선순위 큐에 삽입
        for (int i = 0; i < costs.length; i++) {
            pq.offer(new Edge(costs[i][0], costs[i][1], costs[i][2]));
        }

        while (!pq.isEmpty()) {
            Edge edge = pq.poll();

            // 정점의 부모가 같으면 건너뜀 (사이클이 형성된 것으로 판단)
            if (find(edge.start) == find(edge.end)) continue;
            else {
                union(edge.start, edge.end);
                answer += edge.cost;
            }
        }

        return answer;
    }
    
    // find --> 정점의 부모를 찾아줌.
    public static int find(int p) {
        if (parent[p] == p) return p;
        return parent[p] = find(parent[p]);
    }

    // union --> 정점의 부모를 변경시킴으로써 서로 연결되었다는 것을 표시해줌.
    public static void union(int a, int b) {
        int rootA = find(a);
        int rootB = find(b);

        if (rootA != rootB) parent[rootB] = rootA;
    }
}

참조 : velog 링크


# Python
# 섬과 섬 연결하기
def union(parent, a, b):
    A = find(parent, a)
    B = find(parent, b)

    if A < B:
        parent[B] = A
    else:
        parent[A] = B


# 섬에 사이클 생기는지 판단
def find(parent, x):
    if parent[x] == x:
        return x
    return find(parent, parent[x])


def solution(n, costs):
    parents = [i for i in range(n)]
    costs = sorted(costs, key=lambda x: x[2])

    answer = 0
    while costs:
        city1, city2, cost = costs.pop(0)
        if find(parents, city1) != find(parents, city2):
            union(parents, city1, city2)
            answer += cost

    return answer


print(solution(4, [[0, 1, 1], [0, 2, 2], [1, 2, 5], [1, 3, 1], [2, 3, 8]]))
print(solution(6, [[1, 4, 1], [0, 3, 2], [1, 2, 2], [0, 4, 3], [2, 5, 3], [4, 5, 4], [0, 1, 5], [3, 4, 10]]))
profile
Computer Science!!

2개의 댓글

comment-user-thumbnail
2021년 6월 24일

해당 노드의 부모값이 아니라, 해당 노드의 부모 노드의 부모값을 갱신해줘야 하는군요... 깔끔한 코드 배워갑니다

1개의 답글