์ต์ ์ ์ฅ ํธ๋ฆฌ MST(Minimun Spanning Tree) - ํฌ๋ฃจ์ค์นผ ์๊ณ ๋ฆฌ์ฆ ์๋ฐ ๊ตฌํ
๐ง ์ต์ ์ ์ฅ ํธ๋ฆฌ MST(Minimun Spanning Tree)๋?
์ต์ํ์ ๊ฐ์ค์น๋ฅผ ์ฌ์ฉํ์ฌ ๋ชจ๋ ์ ์ ์ด ์ฐ๊ฒฐ๋์ด ์์ ์ ์๊ฒํ๋ ๊ธฐ๋ฒ์ด๋ค.
์์)
๋์๋ค์ ๋ชจ๋ ๋ค๋ฆฌ๋ก ์ฐ๊ฒฐ๋์ด์์ ๋, ๋ชจ๋ ๋์๋ฅผ ๊ฐ ์ ์๊ฒ ๋ค๋ฆฌ๋ฅผ ์ฐ๊ฒฐํ๋ ์ต์ํ์ ๋ค๋ฆฌ ๊ธธ์ด๋ง์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
(๋์๊ฐ ๊ฐ๋ก๋ฑ์ผ๋ก ๋ค๋ฆฌ๊ฐ ์ ์ ์ผ๋ก ๋ฐ๋์๋ ์๋ค.)
๋ค๋น๊ฒ์ด์ ์ ์ต๋จ ๊ฒฝ๋ก
๋ชจ๋ ์ ์ (node ํน์ vortex)๊ฐ ์ฐ๊ฒฐ๋ ์ ์๋ ๊ฒฝ๋ก ์ค ๊ฐ์ฅ ์ ์ ๊ฐ์ค์น(์ฌ๊ธฐ์ ๊ฑฐ๋ฆฌ)๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ๋ก
์ฃผ์์ฌํญ
์ฌ๊ธฐ์ ์ฐ๊ฒฐ์ด๋ ๋ค๋ฅธ ๋ ธ๋๋ฅผ ๊ฑฐ์ณ์ ๊ฐ๋ ๊ฒ์ ํฌํจํ๋ค.
๊ฐ์ ํน์ ๋ธ๋์น(๋ ธ๋๋ฅผ ์ด์ด์ฃผ๋ ์ , ๊ฑฐ๋ฆฌ)๋ ๋ฐฉํฅ์ฑ์ ๊ฐ์ง ์๋๋ค.(์ฐ๊ฒฐ๋ง ๋์ด์์ ๋ฟ, ์ถ๋ฐ๊ณผ ๋์ฐฉ์ง์ ์ด ๊ณ ์ ๋ ๊ฒ์ ์๋๋ค.)
๐ง ํฌ๋ฃจ์ค์นผ ์๊ณ ๋ฆฌ์ฆ ๋ก์ง(Kruskal's Algorithm Logic)
1. ๊ฐ์ฅ ์ ์ ๊ฐ์ค์น๋ฅผ ์ค๋ฆ์ฐจ์์ผ๋ก ๋์ดํ๋ค.
2. ๊ฐ์ค์น๊ฐ ์ ์ ์์๋๋ก ๊ฒฝ๋ก๋ฅผ ์ ํํด์ ๋ ธ๋๋ค์ ์ด์ด์ค๋ค.
3. ์ํด(circle)์ด ์๊ธฐ์ง ์๊ฒ ์ฃผ์ํ๋ค.
4. ๋ชจ๋ ๋ ธ๋์ ํ์์ด ๋๋๋ฉด ์ข ๋ฃํ๋ค.
๊ฐ์ ์ ์ ๊ฐ์ค์น๋ฅผ ์ค๋ฆ์ฐจ์์ผ๋ก ๋์ดํ๋ค.
์ ๊ทธ๋ฆผ์์ ๊ฐ์ค์น๋ "๊ฑฐ๋ฆฌ"์ด๋ฏ๋ก ๊ฐ์ฅ ์์ ๊ฒฝ๋ก๋ถํฐ ์์๋๋ก ๋์ดํ๋ค.(๊ฐ์ ๊ฐ์ค์น๋ ์์๊ฐ ์๊ด ์๋ค.)
์ฐ๊ฒฐ๋ ๋ ธ๋ | A, D | B, D | B, E | A, E | A, C | C, E | C, D | A, B |
๊ฑฐ๋ฆฌ(๊ฐ์ค์น) | 1 | 2 | 2 | 3 | 3 | 3 | 3 | 5 |
๊ฐ์ค์น๊ฐ ์ ์ ์์๋๋ก ๊ฒฝ๋ก๋ฅผ ์ ํํด์ ๋ ธ๋๋ค์ ์ด์ด์ค๋ค.
์ํด(circle)์ด ์๊ธฐ์ง ์๊ฒ ์ฃผ์ํ๋ค.
์ด๋, ๊ฐ์ค์น 3์ ๊ฐ์ง๋ [A, E]๋ฅผ ์ฐ๊ฒฐํ๋ ๊ฐ์ ์ ์ ํํ๋ฉด ์ํด(circle)์ด ๋ฐ์ํ๋ค.
์ํด์ด๋, ์ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ด ๋ ธ๋๋ค์ด ์ํํ๋ ํํ๊ฐ ๋๋ ๊ฒ์ ์๋ฏธํ๋ค.
A๋ ธ๋์์ E๋ ธ๋๋ก๊ฐ๋ ๊ฒฝ์ฐ๊ฐ ๋ ๊ฐ ์ด์(A->B->E, A->E)์ผ๋ก ์ค๋ณต๋๋ฏ๋ก ํด๋น ๊ฐ์ ์ ์ ํํ์ง ์๋๋ค.
๋ง์ง๋ง ๊ฑฐ๋ฆฌ์ธ 5๋ฅผ ์ ํํ๋ฉด ์ํด์ ์์ฑํ๋ฏ๋ก ์ฐ๊ฒฐํ์ง ์๋๋ค.
๋ชจ๋ ๋ ธ๋์ ํ์์ด ๋๋๋ฉด ์ข ๋ฃํ๋ค.
๐ง ํฌ๋ฃจ์ค์นผ ์๊ณ ๋ฆฌ์ฆ ๊ตฌํ์ ์ํ ๊ธฐ๋ฒ(union-find, union-by-rank, path-compression)
union-find
- find: ์ํด์ ์ด๋ฃจ๋์ง ํ์ธํ๋ค.
- union: ์ํด์ ์ด๋ฃจ์ง ์๋๋ค๋ฉด ์ฐ๊ฒฐํ๋ค.
find
์ํด์ ์ด๋ฃจ๋์ง ์ด๋ป๊ฒ ํ์ธํ ๊น?
=> ์ฐ๊ฒฐํ node์ ์ฐ๊ฒฐ๋ ๋ ๋ค๋ฅธ node๊ฐ ์์ ์ด ์ฐ๊ฒฐ๋ ๋ ๋ค๋ฅธ node์ ์ผ์นํ๋ค๋ฉด ์ํด์ผ ์ด๋ฃฌ๋ค.
์๋ฅผ ๋ค์ด ์ด๋ฒ์ ์ ํ๋ ๊ฐ์ ์ B-C ์ด๋ค.
์ด๋, B ๋ ธ๋๋ A๋ ธ๋์ ์ฐ๊ฒฐ๋์ด ์๋๋ฐ C๋ ธ๋๊ฐ A๋ ธ๋์ ์ฐ๊ฒฐ๋์ด ์๋ค๋ฉด ์ํด์ด ์ด๋ฃฌ๋ค.
์ด๋ ๋ง์น B ๋ ธ๋์ C๋ ธ๋์ ๋ถ๋ชจ ๋ ธ๋๊ฐ A์ธ ํธ๋ฆฌ๊ตฌ์กฐ์ ์ ์ฌํ๋ค.
find ๊ธฐ๋ฒ์ ๋ชจ๋ ๋ ธ๋์ ๋ถ๋ชจ ๋ ธ๋๋ฅผ ์ ๋ ฅ์์ผ ์ ํ๋ ๊ฐ์ ์ ๋ ๋ ธ๋์ ๋ถ๋ชจ๋ ธ๋๊ฐ ์ผ์นํ๋์ง ํ์ธํ๋ ๊ฒ์ด๋ค.
์ ๊ฒฝ์ฐ๋ B๋ ธ๋์ C๋ ธ๋๊ฐ A๋ ธ๋์ ์ฐ๊ฒฐ๋์ด ์๊ธฐ์ ๋ฐ๋ก ์ํด์์ ํ์ธํ ์ ์์ง๋ง ์ค์ ๋ก ๋ ๋ง์ ๋ ธ๋๊ฐ ์๋ค๋ฉด ๋ถ๋ชจ๋ ธ๋์ ๋ถ๋ชจ๋ ธ๋ ๋ ๊ทธ ๋ถ๋ชจ๋ ธ๋๊น์ง ๊ณ์ํด์ ํ์ธํด์ผํ๋ค.
์ ๊ทธ๋ฆผ์ฒ๋ผ B๋ ธ๋์ ๋ถ๋ชจ์ธ D์ ๋ถ๋ชจ์ธ E์ ์ํด์ ์ด๋ฃฐ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
๋ชจ๋ ๋ถ๋ชจ๋ ธ๋๋ค์ ๋ํด์ ๋น๊ต๋ฅผํ๋ฉด ๋ ๋ง์ ๋ฐ๋ณตํ์๋ฅผ ๊ฐ์ง๊ฒ ๋๋ค. ํ์๋ฅผ ์ค์ด๊ธฐ ์ํด์ ๋ชจ๋ ๋ถ๋ชจ ๋ ธ๋๋ฅผ ์ต์ข root๋ ธ๋๋ก ๊ฐฑ์ ํด๊ฐ๋ ๋ฐฉ๋ฒ์ ์ด์ฉํ๋ค.
// find: ๋ฃจํธ ๋
ธ๋๋ฅผ ์ฐพ์๋ด๋ ํจ์
public String find(String node) {
// parh compression ๊ธฐ๋ฒ์ ์ด์ฉ(๋ฃจํธ๋ฅผ ๊ฐ๊ฒ ๋ง๋ฆ)
if(parentNode.get(node) != node) { // ๋ถ๋ชจ๊ฐ ์์ ๊ณผ ๊ฐ์ง ์๋ค๋ฉด, ๋ฃจํธ๊ฐ ์๋
parentNode.put(node, find(parentNode.get(node))); // ์ฌ๊ท๋ฅผ ํตํด ๋ถ๋ชจ์ ๋ถ๋ชจ๋ก ๊ฐฑ์ => ๋ฃจํธ ๋
ธ๋๊ฐ ๊ฐ์์ง
}
return parentNode.get(node); // ์ต์ข
๋ถ๋ชจ ๋
ธ๋๋ ๋ฃจํธ
}
๋น๊ตํ๊ณ ํ๋ ๋ ธ๋๋ค ๋ถ๋ชจ๋ ธ๋๋ ์ต์ข ์ ์ธ root๋ ธ๋๊ฐ ๋๊ณ ์ถํ ๋น๊ตํ ๋ root๋ ธ๋๊ฐ ๋์ผํ์ง๋ง ํ๋ฒ ๋น๊ตํ๋ฉด ๋๊ธฐ์ ํ์ํ์๋ฅผ ์ค ์ผ ์ ์๋ค. ์ด ์ฒ๋ผ ํ๋ฒ ๊ฑฐ์ฒ๊ฐ ๋ฃจํธ๋ฅผ ๊ฐฑ์ ํด ๋ฐ๋ณต ํ์ธ์ ์ค์ด๋ ๊ฒ์ด path compression์ด๋ค.
union
์ํด์ ์ด๋ฃจ์ง ์๋๋ค๋ฉด, ์ฐ๊ฒฐํด์ค ๋จ๊ณ
// union: ๊ฐ์ ์ ์ฐ๊ฒฐ
public void union(String nodeS, String nodeE){
String rootS = find(nodeS);
String rootE = find(nodeE);
// union by rank ๊ธฐ๋ฒ์ ์ด์ฉ
if(rank.get(rootS) > rank.get(rootE)){ // ๋ญํฌ๊ฐ ๋์ ๊ณณ์ ๋ฎ์ ๋ญํฌ๋ฅผ ์ฐ๊ฒฐ
parentNode.put(rootE, rootS);
} else {
parentNode.put(rootS, rootE); // ๋ญํฌ๊ฐ ๊ฐ๋ค๋ฉด, ํ์ชฝ์ ๋ญํฌ๋ฅผ ์ฌ๋ฆฌ๊ณ ์ฐ๊ฒฐ
rank.put(rootE, rank.get(rootE) + 1);
}
}
unionํ๋ ๊ณผ์ ์์๋ union-by-rank ๊ธฐ๋ฒ์ด ์ฌ์ฉ๋๋ค.
find๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์ ํธ๋ฆฌ๊ตฌ์กฐ๋ก node๋ฅผ ์ดํดํ๋๋ฐ ์ด๋ ๋ ธ๋๋ค์ ๊น์ด๋ฅผ rank๋ก ํ์ํด์ค๋ค.
์ฒ์ node์ rank๋ 0์ผ๋ก ์์ํ๋ค.
node๋ฅผ ์ฐ๊ฒฐํ ๋ ๋ญํฌ๊ฐ ๋ฎ์๊ฒ์ ๋์๊ฒ ์๋์ ์ฐ๊ฒฐํ๋ค. ๋ญํฌ๊ฐ ๊ฐ๋ค๋ฉด ํ์ชฝ์ ๋ญํฌ๋ฅผ ๋์ด๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ค.
์ต์ข ์ฝ๋
import java.util.*;
/**
* ์ต์ ์ ์ฅ ํธ๋ฆฌ(minimum spanning tree) ํฌ๋ฃจ์ค์นผ ์๊ณ ๋ฆฌ์ฆ
* union find ์๊ณ ๋ฆฌ์ฆ ์ด์ฉ => ๋ฃจํธ ๋
ธ๋๊ฐ ๊ฐ๋ค๋ฉด ์ด๋ฏธ ์ฐ๊ฒฐ๋ ๋
ธ๋์ด๋ค.
* union by rank ์๊ณ ๋ฆฌ์ฆ ์ด์ฉ => ๋
ธ๋๊ฐ ์ฐ๊ฒฐ๋ ํธ๋ฆฌ์ ๋์ด๋ฅผ ๋ญํฌ๋ก ๋ค๋ฃธ.
* path compression ์ด์ฉ => ๋ฃจํธ ๋
ธ๋๋ฅผ ํ๋ฒ์ ์ฐพ๊ธฐ ์ํ ๊ธฐ๋ฒ. ํ๋ฒ ๊ฑฐ์ณ๊ฐ ๋ฃจํธ๋ฅผ ๊ฐฑ์ (๋ถ๋ชจ์ ๋ถ๋ชจ๋ฅผ ์์ ์ ๋ฃจํธ๋ก ๊ฐฑ์ => ๋ฃจํธ๊ฐ ๊ฐ์์ง)
*
*/
public class Kruskal {
Map<String, String> parentNode = new HashMap<>(); // ๋ถ๋ชจ ๋
ธ๋๋ฅผ ์ ์ฅ
Map<String, Integer> rank = new HashMap<>(); // ๋
ธ๋์ ๋ญํฌ๋ฅผ ์ ์ฅ
// ๊ฐ์ ๊ฐ์ฒด
public static class Edge implements Comparable<Edge> {
int weight; // ์ฐ๊ฒฐ๋ ๋
ธ๋๋ค์ ๊ฐ์ค์น
String nodeS; // ์ฐ๊ฒฐ๋ 2๊ฐ์ ๋
ธ๋ ์ค ํ๋
String nodeE; // ์ฐ๊ฒฐ๋ 2๊ฐ์ ๋
ธ๋ ์ค ํ๋
// ์์ฑ์
public Edge(int weight, String nodeS, String nodeE){
this.weight = weight;
this.nodeS = nodeS;
this.nodeE = nodeE;
}
@Override
public int compareTo(Edge o) {
return this.weight - o.weight; // ๊ฐ์ค์น๋ก ์ค๋ฆ์ฐจ์
}
}
/**
* union find ์๊ณ ๋ฆฌ์ฆ
*/
// find: ๋ฃจํธ ๋
ธ๋๋ฅผ ์ฐพ์๋ด๋ ํจ์
public String find(String node) {
// parh compression ๊ธฐ๋ฒ์ ์ด์ฉ(๋ฃจํธ๋ฅผ ๊ฐ๊ฒ ๋ง๋ฆ)
if(parentNode.get(node) != node) { // ๋ถ๋ชจ๊ฐ ์์ ๊ณผ ๊ฐ์ง ์๋ค๋ฉด, ๋ฃจํธ๊ฐ ์๋
parentNode.put(node, find(parentNode.get(node))); // ์ฌ๊ท๋ฅผ ํตํด ๋ถ๋ชจ์ ๋ถ๋ชจ๋ก ๊ฐฑ์ => ๋ฃจํธ ๋
ธ๋๊ฐ ๊ฐ์์ง
}
return parentNode.get(node); // ์ต์ข
๋ถ๋ชจ ๋
ธ๋๋ ๋ฃจํธ
}
// union: ๊ฐ์ ์ ์ฐ๊ฒฐ
public void union(String nodeS, String nodeE){
String rootS = find(nodeS);
String rootE = find(nodeE);
// union by rank ๊ธฐ๋ฒ์ ์ด์ฉ
if(rank.get(rootS) > rank.get(rootE)){ // ๋ญํฌ๊ฐ ๋์ ๊ณณ์ ๋ฎ์ ๋ญํฌ๋ฅผ ์ฐ๊ฒฐ
parentNode.put(rootE, rootS);
} else {
parentNode.put(rootS, rootE); // ๋ญํฌ๊ฐ ๊ฐ๋ค๋ฉด, ํ์ชฝ์ ๋ญํฌ๋ฅผ ์ฌ๋ฆฌ๊ณ ์ฐ๊ฒฐ
rank.put(rootE, rank.get(rootE) + 1);
}
}
// ์ด๊ธฐํ
public void init(String node) {
parentNode.put(node, node); // ๋ถ๋ชจ๊ฐ ์์ ์ธ ๋
ธ๋๋ ๋ฃจํธ
rank.put(node, 0); // ์ด๊ธฐ ๋ญํฌ๋ 0
}
public ArrayList<Edge> kruskalFunc(ArrayList<String> vetices, ArrayList<Edge> edgeds) {
ArrayList<Edge> list = new ArrayList<>();
// ์ด๊ธฐํ
for(String item : vetices) {
init(item);
}
// ์ ๋ ฌ
Collections.sort(edgeds);
// ๊ฐ์ ์ฐ๊ฒฐ
for(Edge edge : edgeds) {
if(find(edge.nodeS) != find(edge.nodeE)) { // ๋ฃจํธ ๋
ธ๋๊ฐ ๋ค๋ฅด๋ค๋ฉด ์ํดํ์ฑ์ ํ์ง์์
union(edge.nodeS, edge.nodeE); // ๊ฐ์ ์ ์ฑํํด์ ๋
ธ๋๋ฅผ ์ฐ๊ฒฐ
list.add(edge); // ์ฑํํ ๊ฐ์ ์ ๊ฒฐ๊ณผ์ ๋ด๊ธฐ
}
}
return list;
}
}