MST๋?
์ต์ ์ ์ฅ ํธ๋ฆฌ(Minimum Spanning Tree)๋ก ๊ฐ์ค ๊ทธ๋ํ(Weight Graph)์์ ๊ฐ์ฅ ์ ์ ๋น์ฉ(Weight)์ผ๋ก ๋ชจ๋ ์ ์ (Vertex)์ผ๋ก ์ด๋ํ ์ ์๋ ๋ถ๋ถ ๊ทธ๋ํ(Sub Graph)์ด๋ค. MST๋ ๊ฐ ์ ์ ์์ ์ ์ ์ฌ์ด์ ํ๋์ ๊ฐ์ (Edge)๋ง ํ์ํ๋ฏ๋ก ์ด N-1 ๊ฐ์ ๊ฐ์ ์ ๊ฐ์ง๊ฒ ๋๋ฏ๋ก ๋ง์น ํธ๋ฆฌ์ ํํ๋ฅผ ํ๊ณ ์์ด์ ํธ๋ฆฌ๋ผ๋ ์ด๋ฆ์ด ๋ถ๋๋ค.
ํฌ๋ฃจ์ค์นผ ์๊ณ ๋ฆฌ์ฆ
1. ๋ชจ๋ ๊ฐ์ ์ ๋น์ฉ์ด ์ ์ ์์๋ฅผ ๊ธฐ์ค์ผ๋ก ์ ๋ ฌํ๋ค. - Sort
2. ๊ฐ์ ์ ๋ถ์ ์ ์ u์ v๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ถ๋ชจ๋ฅผ ์ฐพ๋๋ค. - Find
3. ์ ์ u์ ๋ถ๋ชจ์ ์ ์ v์ ๋ถ๋ชจ๊ฐ ๋ค๋ฅด๋ค๋ฉด ์๋ก ๋ค๋ฅธ ์งํฉ์ ์ํด์์ง๋ง, 1๋ฒ ๊ณผ์ ์ผ๋ก ์ธํด ํด๋น ๊ฐ์ ์ด ๋ ์ ์ ์ ์ต์ ๋น์ฉ์ ๊ฐ์ ์์ ์ ์ ์์ผ๋ฏ๋ก ํ๋์ ์งํฉ์ผ๋ก ํฉ์น๋ค. - Union
+ Union ๊ณผ์ ์์ ์ด์ด์ง ๊ฐ์ ์ด ์ต์ ๋น์ฉ์ด๋ฏ๋ก ํด๋น ๊ฐ์ ์ ๋ณด๋ก MST์ ์ด ๋น์ฉ์ด๋ ๊ฒฝ๋ก๋ฅผ ์ ์ ์๋ค!
+ 1๋ฒ Sortํ๋ ๊ณผ์ ์ ๋ฐฐ์ด๋ก ํ ์๋ ์์ง๋ง, Priority Queue๋ก๋ ํ ์ ์๋ค.
ํฌ๋ฃจ์ค์นผ ๋ ธ๋
package com.study.datastructrue.graph.mst.kruskal;
public class KruskalNode implements Comparable<KruskalNode> {
int u;
int v;
int weight;
public KruskalNode(int u, int v, int weight) {
this.u = u;
this.v = v;
this.weight = weight;
}
@Override
public int compareTo(KruskalNode o) {
return this.weight - o.weight;
}
}
์ ๋ ฌ์ ์ํด Comparable ์ธํฐํ์ด์ค์ ๋ฉ์๋๋ฅผ ๊ตฌํํด์ค๋ค.
Kruskal Algorithm - Array
package com.study.datastructrue.graph.mst.kruskal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
public class ArrayKruskal {
private List<KruskalNode> edges;
private int[] parent, ranks;
private int minimumDistance;
private Set<Integer> path;
public ArrayKruskal(int size) {
this.edges = new ArrayList<>();
this.parent = new int[size + 1];
this.ranks = new int[size + 1];
this.minimumDistance = Integer.MAX_VALUE;
this.path = new LinkedHashSet<>();
initParent(size + 1);
}
public void update() {
this.minimumDistance = 0;
Collections.sort(this.edges);
for (KruskalNode node : this.edges) {
int parentA = find(node.u);
int parentB = find(node.v);
if (parentA != parentB) {
union(parentA, parentB);
this.minimumDistance += node.weight;
this.path.add(node.u);
this.path.add(node.v);
}
}
}
public int getMinimumDistance() {
return minimumDistance;
}
public void printTrace() {
System.out.println(path.toString());
}
public void add(int u, int v, int w) {
this.edges.add(new KruskalNode(u, v, w));
}
private void initParent(int size) {
for (int i = 0; i < size; i++) {
this.parent[i] = i;
this.ranks[i] = 0; // rank ์ด๊ธฐํ
}
}
private int find(int x) {
if (x != parent[x]) {
parent[x] = find(parent[x]);
}
return parent[x];
}
private void union(int x, int y) {
if (ranks[x] < ranks[y]) {
int temp = ranks[x];
ranks[x] = ranks[y];
ranks[y] = temp;
}
parent[y] = x;
if(ranks[x] == ranks[y]) {
ranks[x] = ranks[y] + 1;
}
}
}
1. find ์ฐ์ฐ์ ๋ถ๋ชจ๋ฅผ ์ฐพ์ ๋๊น์ง recursion์ ์งํํ๋ค. (์ฑ๋ฅ ๊ฐ์ , ๊ฒฝ๋ก์์ถ ๊ธฐ๋ฒ ์ ์ฉ)
2. ์ ์ u์ ์ ์ v๊ฐ ๋ค๋ฅผ ๊ฒฝ์ฐ Union ์ฐ์ฐ์ด ์งํ๋๋ค. ์ด ๋, Rank๋ก ํธ๋ฆฌ์ ๋์ด๋ฅผ ์ ์ฅํ๋ฉด์ ๊ฐ tree์ ๊ณ์ธต์ ํํํ ์ ์๋ค. (Union ์ฐ์ฐ์ ๊ฐ์ )
3. Set ์๋ฃ๊ตฌ์กฐ๋ฅผ ์ด์ฉํด Union ์ฐ์ฐ๋ง๋ค ๋งค ๋ ธ๋๋ฅผ ์ถ๊ฐํด ์ค๋ณต๋ ๋ ธ๋๋ ๋ฌด์ํ๊ณ ๊ฒฝ๋ก๋ฅผ ๊ตฌํ ์ ์๋ค.
Kruskal Algorithm - Priority Queue
package com.study.datastructrue.graph.mst.kruskal;
import java.util.LinkedHashSet;
import java.util.PriorityQueue;
import java.util.Set;
public class PriorityQueueKruskal {
private PriorityQueue<KruskalNode> edges;
private Set<Integer> path;
private int[] parent, ranks;
private int minimumDistance;
public PriorityQueueKruskal(int size) {
this.edges = new PriorityQueue<>();
this.parent = new int[size + 1];
this.ranks = new int[size + 1];
this.minimumDistance = Integer.MAX_VALUE;
this.path = new LinkedHashSet<>();
initParent(size + 1);
}
public void update() {
this.minimumDistance = 0;
PriorityQueue<KruskalNode> temp = new PriorityQueue<>(this.edges);
while (!temp.isEmpty()) {
KruskalNode node = temp.poll();
int parentA = find(node.u);
int parentB = find(node.v);
if (parentA != parentB) {
union(parentA, parentB);
this.minimumDistance += node.weight;
this.path.add(node.u);
this.path.add(node.v);
}
}
}
public int getMinimumDistance() {
return minimumDistance;
}
public void printTrace() {
System.out.println(path.toString());
}
public void add(int u, int v, int w) {
this.edges.add(new KruskalNode(u, v, w));
}
private void initParent(int size) {
for (int i = 0; i < size; i++) {
this.parent[i] = i;
}
}
private int find(int x) {
if (x == parent[x]) {
return x;
}
return parent[x] = find(parent[x]);
}
private void union(int x, int y) {
if (x == y) {
return;
}
if (ranks[x] < ranks[y]) {
int temp = ranks[x];
ranks[x] = ranks[y];
ranks[y] = temp;
}
parent[y] = x;
if(ranks[x] == ranks[y]) {
ranks[x] = ranks[y] + 1;
}
}
}
- Priority Queue๋ poll ์ฐ์ฐ์ ํตํด ์ต์ ์ ์ฅ ํธ๋ฆฌ๋ฅผ ๊ฐฑ์ ํ ์ ์์ง๋ง, ์ผํ์ฉ์ด๋ฏ๋ก ๋ณต์ฌํ๊ฒ ๋๋ ์๊ฐ์ด ๋ฐ์ํ๋ค.
- ๋ฐ๋ก ์ ๋ ฌ ๊ฐ์ฒด๋ฅผ ๋ถ๋ฅด์ง ์์๋ ๋๋ค๋ ์ฅ์ ์ด ์์ง๋ง ์.. Priority Queue๊ฐ ํธํ๋ฉด ์ด ๋ฐฉ๋ฒ์, ์๋๋ฉด ArrayList ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์ ์๋๋ก ํ๋ ค๊ณ ๋๊ฐ์ง ๋ฐฉ๋ฒ์ ๋ค ์์ฑํ๋ค.
์ค์ฌ์ฉ Main
package com.study.datastructrue.graph.mst.kruskal;
public class Main {
public static void main(String[] args) {
PriorityQueueKruskal pKruskal = new PriorityQueueKruskal(5);
pKruskal.add(1, 2, 6); pKruskal.add(1, 3, 3);
pKruskal.add(1, 4, 1); pKruskal.add(2, 5, 4);
pKruskal.add(3, 4, 2); pKruskal.add(3, 5, 5);
pKruskal.add(4, 5, 7); pKruskal.update();
System.out.println(pKruskal.getMinimumDistance());
pKruskal.printTrace();
ArrayKruskal aKruskal = new ArrayKruskal(5);
aKruskal.add(1, 2, 6); aKruskal.add(1, 3, 3);
aKruskal.add(1, 4, 1); aKruskal.add(2, 5, 4);
aKruskal.add(3, 4, 2); aKruskal.add(3, 5, 5);
aKruskal.add(4, 5, 7); aKruskal.update();
System.out.println(aKruskal.getMinimumDistance());
aKruskal.printTrace();
}
}
ํ๋ฆผ ์๊ณ ๋ฆฌ์ฆ
1. ๋ชจ๋ ๊ฐ์ ์ด ๋น์ฉ์ด ์ ์ ์์๋ก ์ ๋ ฌํ๋ค. - Sort
2. ์์ ์ ์ ์ ์ ํ๋ค.
3. ์์ ์ ์ ์ผ๋ก๋ถํฐ ๋ฐฉ๋ฌธํ์ง ์์ ์ ์ ๊ณผ ์ฐ๊ฒฐ๋ ๊ฐ์ ๋ง ์ต์ ๋น์ฉ ๊ฐ์ ์ผ๋ก ์ฑํํ๋ค.
4. 3๋ฒ์์ ๊ตฌํ ์ ์ ๊ณผ์ ์ต์ ๋น์ฉ ๊ฐ์ ์ ๊ตฌํ๋ ๊ณผ์ ์ ๋ฐ๋ณตํ๋ค.
+ 3๋ฒ, 4๋ฒ ๊ณผ์ ์ ๋ฐ๋ณตํ๋ ๊ณผ์ ์ ํ๋ ค๋ฉด PriorityQueue๋ก ๊ตฌํํ๋ ๊ฒ์ด ์ข๋ค.
+ ์ต์ ๋น์ฉ์ ๊ธฐ์ค์ผ๋ก ๋ฐฉ๋ฌธํ์ง ์์ ์ ์ ๋ง ๋ฐฉ๋ฌธํ๋ฏ๋ก ์ต์ ๋น์ฉ ๊ฒฝ๋ก๋ฅผ ๊ตฌํ ์ ์๋ค.
ํ๋ฆผ ๋ ธ๋
package com.study.datastructrue.graph.mst.prim;
public class PrimNode implements Comparable<PrimNode>{
int v;
int weight;
public PrimNode(int v, int weight) {
this.v = v;
this.weight = weight;
}
@Override
public int compareTo(PrimNode o) {
return this.weight - o.weight;
}
}
- ํฌ๋ฃจ์ค์นผ์ ๊ฐ์ ์ ๋น์ฉ์ ๊ธฐ์ค์ผ๋ก ์ ๋ ฌํ๊ธฐ ๋๋ฌธ์ u, v ์ ๋ณด๊ฐ ๋ชจ๋ ํ์ํ๋ค.
- ํ๋ฆผ์ ๋ค์ ์ ์ ๊น์ง์ ๋น์ฉ์ ๊ธฐ์ค์ผ๋ก ์ ๋ ฌํ๊ธฐ ๋๋ฌธ์ u ์ ๋ณด๊ฐ ํ์ ์๋ค.
Prim Algorithm
package com.study.datastructrue.graph.mst.prim;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.PriorityQueue;
public class Prim {
private List<PrimNode>[] graph;
private List<Integer> path;
private boolean[] visited;
private int minimumDistance;
public Prim(int size) {
this.graph = new List[size + 1];
this.path = new ArrayList<>();
this.visited = new boolean[size + 1];
this.minimumDistance = Integer.MAX_VALUE;
initGraph(size);
}
private void initGraph(int size) {
for (int i = 0; i <= size; i++) {
this.graph[i] = new ArrayList<>();
}
}
public void add(int u, int v, int w) {
this.graph[u].add(new PrimNode(v, w));
this.graph[v].add(new PrimNode(u, w));
}
public void update(int start) {
Arrays.fill(visited, false);
path.clear();
this.minimumDistance = 0;
PriorityQueue<PrimNode> pq = new PriorityQueue<>();
pq.offer(new PrimNode(start, 0));
while(!pq.isEmpty()) {
PrimNode node = pq.poll();
if (visited[node.v]) continue;
visited[node.v] = true;
this.minimumDistance += node.weight;
path.add(node.v);
for (PrimNode next: graph[node.v]) {
if (!visited[next.v]) {
pq.offer(next);
}
}
}
}
public int getMinimumDistance() {
return this.minimumDistance;
}
public void printTrace() {
for (int v: path) {
System.out.print(v + " ");
}
System.out.println();
}
}
- Path๋ ๋ฐฉ๋ฌธํ์ง ์์ ์ ์ ์์๋๋ก ์ต์ ๋น์ฉ์ผ๋ก ์ฑํ๋ ํ ๋ List ๋ฅผ ํตํด ์ถ๊ฐํ๋ฉด ๋๋ค.
Main
package com.study.datastructrue.graph.mst.prim;
import com.study.datastructrue.graph.mst.kruskal.PriorityQueueKruskal;
public class Main {
public static void main(String[] args) {
Prim prim = new Prim(5);
prim.add(1, 2, 6); prim.add(1, 3, 3);
prim.add(1, 4, 1); prim.add(2, 5, 4);
prim.add(3, 4, 2); prim.add(3, 5, 5);
prim.add(4, 5, 7); prim.update(1);
System.out.println(prim.getMinimumDistance());
prim.printTrace();
}
}
๋ณดํต ๊ฐ์ ์ด ๋ง์ ๊ฒฝ์ฐ, ๊ฐ์ ์ ๊ธฐ์ค์ผ๋ก ์ ๋ ฌํ๋ ํฌ๋ฃจ์ค์นผ
์ ์ ์ด ๋ง์ ๊ฒฝ์ฐ, ์ ์ ์ ๊ธฐ์ค์ผ๋ก ์ ๋ ฌํ๋ ํ๋ฆผ์ ์ฌ์ฉํ๋ฉด ํจ์จ์ ์ด๊ฒ ๋ค.
'์๊ณ ๋ฆฌ์ฆ > ์๊ณ ๋ฆฌ์ฆ ์ข ๋ฅ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
CCW (Counter Clock Wise) (0) | 2025.06.30 |
---|---|
Unbounded Knapsack (๋ฌดํ ๋ฐฐ๋ญ) (1) | 2025.06.28 |
[์ต๋จ๊ฒฝ๋ก] Bellman-Ford Algorithm (0) | 2024.07.06 |
[์ด๋ถ ํ์] ์ด๋ถ ํ์(Binary Search) ์ด๋ ? (0) | 2024.02.01 |