복습 요망!
1. 비용이 최소인 것들 부터 탐색 시작
2. 선이 n-1개가 되면 탐색 종료
즉, 비용이 최소인 것들만 n-1개 될 때까지 합하자. 라는 풀이 방법을 세웠다. 왜냐하면 문제에서
- 같은 연결은 두 번 주어지지 않습니다. 또한 순서가 바뀌더라도 같은 연결로 봅니다. 즉 0과 1 사이를 연결하는 비용이 주어졌을 때, 1과 0의 비용이 주어지지 않습니다.
- 모든 섬 사이의 다리 건설 비용이 주어지지 않습니다. 이 경우, 두 섬 사이의 건설이 불가능한 것으로 봅니다.
이러한 조건이 주어졌기 때문에 내 풀이가 정답인 줄 알았으나 아니였다...
다른 사람의 풀이는 살펴보니 크루스칼 알고리즘
을 이용해야했다. 이 문제는 MST(Minimum Spanning Tree)의 기본 개념을 활용하는 문제이다. MST 문제를 해결하기 위해서는 크루스칼 알고리즘
을 이용하자.
크루스칼 알고리즘
임을 기억하자!비용이 최소인 것들을 오름차순으로 정렬
비용이 최소인 것 들부터 간선을 연결한다. 이 때 사이클이 형성되지 않도록 연결해야한다!
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]]))
해당 노드의 부모값이 아니라, 해당 노드의 부모 노드의 부모값을 갱신해줘야 하는군요... 깔끔한 코드 배워갑니다