프로그래머스 코딩테스트 그리디 05 - 섬 연결하기
문제 설명
n개의 섬 사이에 다리를 건설하는 비용(costs)이 주어질 때, 최소의 비용으로 모든 섬이 서로 통행 가능하도록 만들 때 필요한 최소 비용을 return 하도록 solution을 완성하세요.
다리를 여러 번 건너더라도, 도달할 수만 있으면 통행 가능하다고 봅니다. 예를 들어 A 섬과 B 섬 사이에 다리가 있고, B 섬과 C 섬 사이에 다리가 있으면 A 섬과 C 섬은 서로 통행 가능합니다.
제한사항
- 섬의 개수 n은 1 이상 100 이하입니다.
- costs의 길이는
((n-1) * n) / 2
이하입니다. - 임의의 i에 대해, costs[i][0] 와 costs[i] [1]에는 다리가 연결되는 두 섬의 번호가 들어있고, costs[i] [2]에는 이 두 섬을 연결하는 다리를 건설할 때 드는 비용입니다.
- 같은 연결은 두 번 주어지지 않습니다. 또한 순서가 바뀌더라도 같은 연결로 봅니다. 즉 0과 1 사이를 연결하는 비용이 주어졌을 때, 1과 0의 비용이 주어지지 않습니다.
- 모든 섬 사이의 다리 건설 비용이 주어지지 않습니다. 이 경우, 두 섬 사이의 건설이 불가능한 것으로 봅니다.
- 연결할 수 없는 섬은 주어지지 않습니다.
입출력 예
n | costs | return |
---|---|---|
4 | [[0,1,1],[0,2,2],[1,2,5],[1,3,1],[2,3,8]] | 4 |
풀이
원하는 값을 얻기위해선
- 다리의 비용을 기준으로 오름차순 정렬을 한다.
- 섬과 섬사이에 다리가 연결될 때마다 이를 기억해야한다.
- 다리를 연결하는 판별 기준은 다리를 연결함에 따라 섬들 사이에 통로가 순환 가능한 cycle 형태로 이루어진다면 다리를 연결하면 안된다.
이는 그래프 내의 모든 정점들을 가장 적은 비용으로 연결하기 위한 알고리즘 을 구현하는 것이다. 즉 최소 신장 트리(MST) 문제이므로 크루스칼 알고리즘을 이용하면 된다.
알고리즘 구현 전에 생각을 해보면서 두 노드들이 연결되어 하나의 노드가 되도록 구현하면 될 것 같았는데 크루스칼 알고리즘을 알게되어서 이를 적용했더니 매우 간단하게 해결이 되었다.
parents 배열을 통해 각 노드의 부모 노드를 가리키도록 했는데 재귀형태로 구현하면 이러한 배열이 없어도 될 것 같다.
코드(Python)
def union(parents, i1, i2):
ex_parents = parents[i2]
for i in range(len(parents)):
if parents[i] == ex_parents:
parents[i] = parents[i1]
def find(parents, i1, i2):
if parents[i1] == parents[i2]:
return False
else:
return True
def solution(n, costs):
answer = 0
costs.sort(key=lambda x: x[2])
parents = [i for i in range(n)]
for i1, i2, cost in costs:
if find(parents, i1, i2):
union(parents, i1, i2)
answer+=cost
return answer
코드(Java)
import java.util.Arrays;
class Greedy_05_Solution {
static void union(int[] parents, int i1, int i2) {
int ex_parents = parents[i2];
for (int i = 0; i < parents.length; i++) {
if (parents[i] == ex_parents) {
parents[i] = parents[i1];
}
}
}
static boolean find(int[] parents, int i1, int i2) {
if (parents[i1] == parents[i2])
return false;
else
return true;
}
public int solution(int n, int[][] costs) {
int answer = 0;
int[] parents = new int[n];
for (int i = 0; i < n; i++) {
parents[i] = i;
}
Arrays.sort(costs, (c1, c2) -> c1[2] - c2[2]);
for (int[] island : costs) {
if (find(parents, island[0], island[1])) {
union(parents, island[0], island[1]);
answer += island[2];
}
}
return answer;
}
}
댓글남기기