2 분 소요

최소 신장 트리(Minimum Spanning Tree)

1) 그래프에서 모든 정점을 포함하고, 2) 정점 간 서로 연결이 되며, 3) 사이클이 존재하지 않는 그래프

=> 정점의 갯수가 n개일 때, 간선이 n-1개가 된다

=> 이런 신장 트리 중 가중치의 합이 최소가 되는 신장 트리 : **최소 신장 트리 **


1) 크루스칼 알고리즘
import java.util.* ; 
class Solution {
    
    public int[] parent ; 
    public int find(int i){
        if(parent[i] == i)
            return i ; 
        else return parent[i] = find(parent[i]) ; 
    } 
    
    public void union(int a, int b){
        int parent_a = find(a) ; // a의 부모 
        int parent_b = find(b) ; // b의 부모 
        
        // 1 1 1 5 5 
        // 1 2 3 4 5 
        if(parent_a != parent_b)
            // parent[b] = parent_a ; --> b가 속한 집합의 루트를 a의 부모로 설정 (b원소를 a로 이동 ; a와 b는 다른 집합)
            parent[parent_b]  // parent[find(b)] b의 루트
            = parent_a ; 
        // b가 속한 집합의 루트 자체를 a로 변경  
    }
    
    public int solution(int n, int[][] costs) {
        
        // part 1. 초기 상태
        parent = new int[n] ; 
        for(int i = 0 ; i < n ; i++){
            parent[i] = i ; 
        }
        
        // part 2. 가중치 기준으로 정렬 
        Arrays.sort(costs,  (o1, o2) -> o1[2] - o2[2]) ; 
        
        // part 3. 최소 신장 비용 구하기 
        int answer = 0 ; 
        for(int i = 0 ; i < costs.length ; i++){
            if(find(costs[i][0]) != find(costs[i][1])){
                union(costs[i][0], costs[i][1]) ; 
                answer += costs[i][2] ; 
            }
        }
        return answer ; 
    } // solution 
} // class 


※ 루트 노드 설정
 public void union(int a, int b){
        int parent_a = find(a) ; // a의 부모 
        int parent_b = find(b) ; // b의 부모 
        
       
        if(parent_a != parent_b)
            // parent[b] = parent_a ; 
            parent[parent_b] = parent_a ; 
    }
  • parent[b] = parent_a : b가 속한 집합의 루트를 a의 부모로 설정 (b원소를 a로 이동 ; a와 b는 다른 집합)

반례

parent: 1 1 1 5 5 nodes: 1 2 3 4 5

  • parent[parent_b] = parent_a : b가 속한 집합의 루트 자체를 a로 변경


2) 프림 알고리즘
import java.util.* ; 
public class 프림알고리즘 {

	public class Node implements Comparable<Node>{
		int index ; 
		int cost ; 
		
		public Node(int index, int cost) {
			this.index = index ; 
			this.cost = cost ; 
		}
		@Override
		public int compareTo(Node other) {
			return this.cost - other.cost; 
		}	
	}
	
	public List<List<Node>> graph = new ArrayList<>() ; 
	
	public int solution(int n, int[][] costs) {
		
		// 초기화 (그래프 만들기) 
		for(int i = 0 ; i < n ; i++) {
			graph.add(new ArrayList<>()) ; 
		}
		for(int i = 0 ; i < costs.length ; i++) {
			int from = costs[i][0] ; 
			int to = costs[i][1] ; 
			int val = costs[i][2] ; 
			
			graph.get(from).add(new Node(to, val)); 
			graph.get(to).add(new Node(to, val)) ; 
		}
		
		// 프림 알고리즘 
		boolean[] visited = new boolean[n] ; // 각 노드만큼 크기의 방문여부배열
		PriorityQueue<Node> q = new PriorityQueue<>() ; 
		q.add(new Node(0,0)) ; // 검사 시작 노드 
		
		int answer = 0 ; 
		while(!q.isEmpty()) {
			Node cur = q.poll() ; // 가중치가 가장 작은 노드 반환 
			if(visited[cur.index]) continue ; 
			
			visited[cur.index] = true ; 
			answer += cur.cost ;  
			// a 노드에 부속된 간선 중 가능 작은 값이므로 answer에 누적 
			// b 노드로 확대 
			
			// 인접 노드 큐에 추가  
			for(int i = 0 ; i < graph.get(cur.index).size(); i++) {
				int next = graph.get(cur.index).get(i).index ; 
				int cost = graph.get(cur.index).get(i).cost ; 
				if(visited[next]) continue ; // 해당 인접 노드는 큐에 추가 X 
				q.add(new Node(next, cost)) ; 
			} // for 
		} // while
		return answer ; 
	} 
}

댓글남기기