Coding/알고리즘
[알고리즘] 최소 신장 트리
ryureeru
2022. 11. 8. 20:25
최소 신장 트리
- Minimum Spanning Tree (MST)
- 그래프 상의 모든 노드들을 최소 비용으로 연결하는 방법
1. 크루스칼 (Kruskal)
- 간선 중 최솟값을 가진 간선부터 연결한다 (간선들 정렬하고 시작)
- 사이클이 발생하면 다른 간선을 선택한다
- 간선 수가 적을 때 사용
- 알고리즘 복잡도 : O(간선 수 * log(간선 수))
static int parents[];
public int kruskal(int[][] data, int v, int e) {
int weightSum = 0;
// 간선 가중치 오름차순 정렬
Arrays.sort(data, (x, y) -> (x[2] - y[2]));
// union-find 배열 초기화
parents = new int[v + 1];
for (int i = 1; i < v; i++) {
parents[i] = i;
}
for (int i = 0; i < e; i++) {
// 사이클 발생하지 않으면 연결하고 weight 업데이트
if (find(data[i][0]) != find(data[i][1])) {
union(data[i][0], data[i][1]);
weightSum += data[i][2];
}
}
return weightSum;
}
public void union(int a, int b) {
int aP = find(a);
int bP = find(b);
if (aP != bP) {
parents[aP] = bP;
}
}
public static int find(int a) {
// 부모가 자기 자신이면 그냥 return
if (a == parents[a]) {
return a;
}
// 자기 자신이 아니라면 parents 타고타고 들어가기
return parents[a] = find(parents[a]);
}
2. 프림 (Prim)
- 임의의 노드에서 시작
- 연결된 노드들의 간선 중 낮은 가중치를 갖는 갖는 간선을 선택한다
- 간선 수가 많을 때 사용
- 알고리즘 복잡도 : O(간선 수 * log(노드 수))
class Node {
int to;
int weight;
public Node(int to, int weight) {
this.to = to;
this.weight = weight;
}
}
public int prim(int[][] data, int v, int e) {
int weightSum = 0;
// 그래프 구성
ArrayList<ArrayList<Node>> graph = new ArrayList<>();
for (int i = 0; i < v + 1; i++) {
graph.add(new ArrayList<>());
}
for (int i = 0; i < e; i++) {
graph.get(data[i][0]).add(new Node(data[i][1], data[i][2]));
graph.get(data[i][1]).add(new Node(data[i][0], data[i][2]));
}
boolean[] visited = new boolean[v + 1];
PriorityQueue<Node> pq = new PriorityQueue<>((x, y) -> x.weight - y.weight);
pq.offer(new Node(1, 0));
int cnt = 0;
while (!pq.isEmpty()) {
Node cur = pq.poll();
cnt += 1;
// 방문한적 있는 노드면 continue
if (visited[cur.to]) {
continue;
}
visited[cur.to] = true;
weightSum += cur.weight;
// 모든 노드 다 연결했으면 return
if (cnt == v) {
return weightSum;
}
// 연결된 노드들 중 방문하지 않은 노드 찾기
for (int i = 0; i < graph.get(cur.to).size(); i++) {
Node adjNode = graph.get(cur.to).get(i);
if (visited[adjNode.to]) { // 방문했으면 continue
continue;
}
pq.offer(adjNode);
}
}
return weightSum;
}