네트워크 연결
풀이
- 크루스칼 알고리즘을 이용한다.
- 크루스칼 알고리즘은 union-find 자료구조를 인지하고 있으면 쉽게 해결가능하다.
- union-find 링크
- 최소간선 비용을 구해야하기 때문에 비용에 대한 오름차순을 선행한다.
- 반복을 수행하면서 차근차근 간선에 관한 데이터를 추출하고 로직을 수행한다.
- 오랜만에 풀어보는 MST 문제인데도 불구하고 원솔브로 풀어서 스스로도 놀랐다.
- 크루스칼 알고리즘이 아닌 프림 알고리즘으로 해결 가능하다.
- 프림 알고리즘은 현재 선택한 정점을 기준 갈 수 있는 타 정점들의 비용값을 초기화
- 그 비용 값중에서 가장 낮은 값을 선택하고 그 정점을 방문
- 현재 내가 방문한 정점들에서 갈 수 있는 정점들의 비용을 다시 초기화
- 위의 로직을 반복
크루스칼 알고리즘
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.StringTokenizer; public class Main { static InputStreamReader isr; static BufferedReader br; static OutputStreamWriter osw; static BufferedWriter bw; static StringTokenizer st; static int[]parent = null; static int[]size = null; public static void main(String[] args) throws IOException { isr = new InputStreamReader(System.in); br = new BufferedReader(isr); osw = new OutputStreamWriter(System.out); bw = new BufferedWriter(osw); int n = Integer.parseInt(br.readLine()); int m = Integer.parseInt(br.readLine()); parent = new int[n + 1]; size = new int[n + 1]; for(int i = 0; i <= n; i++) { parent[i] = i; size[i] = 1; } /** 간선에 대한 정보 **/ ArrayList<Edge> list = new ArrayList<Edge>(); for(int i = 0; i < m; i++) { st = new StringTokenizer(br.readLine()); int a = Integer.parseInt(st.nextToken()); int b = Integer.parseInt(st.nextToken()); int cost = Integer.parseInt(st.nextToken()); list.add(new Edge(a, b, cost)); } /** 비용 오름차순 정렬 **/ Collections.sort(list); int result = process(list); bw.write(result + "\n"); bw.flush(); bw.close(); br.close(); } private static int process(ArrayList<Edge> list) { int sumMinCost = 0; /** 비용이 오름차순으로 정렬된 간선 획득 **/ for(int i = 0; i < list.size(); i++) { Edge edge = list.get(i); int nodeA = edge.s; int nodeB = edge.e; int cost = edge.cost; int parentOnNodeA = find(nodeA); int parentOnNodeB = find(nodeB); /** 사이클 형성 => 패스 **/ if(parentOnNodeA == parentOnNodeB) { continue; } /** 사이클 미형성 => 합치기 **/ union(parentOnNodeA, parentOnNodeB); sumMinCost += cost; }// for return sumMinCost; } /** 해당 노드의 부모노드를 찾는다. **/ private static int find(int node) { if(parent[node] == node) { return node; } return parent[node] = find(parent[node]); } /** 주어진 두 개의 노드를 합친다. **/ private static void union(int a, int b) { if(size[a] < size[b]) { parent[a] = b; size[b] += size[a]; } else { parent[b] = a; size[a] += size[b]; } } } class Edge implements Comparable<Edge>{ public int s; public int e; public int cost; public Edge(int s, int e, int cost) { this.s = s; this.e = e; this.cost = cost; } @Override public int compareTo(Edge e) { /** cost 오름차순 **/ return cost - e.cost; } } | cs |
프림 알고리즘
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.StringTokenizer; public class Main { static InputStreamReader isr; static BufferedReader br; static OutputStreamWriter osw; static BufferedWriter bw; static StringTokenizer st; static int[]visited = null; static int[]distance = null; static int n = 0; static int m = 0; public static void main(String[] args) throws IOException { isr = new InputStreamReader(System.in); br = new BufferedReader(isr); osw = new OutputStreamWriter(System.out); bw = new BufferedWriter(osw); n = Integer.parseInt(br.readLine()); m = Integer.parseInt(br.readLine()); /** 방문배열 **/ visited = new int[n + 1]; Arrays.fill(visited, 0); /** 최단비용거리 **/ distance = new int[n + 1]; Arrays.fill(distance, Integer.MAX_VALUE); ArrayList<ArrayList<Edge>> list = new ArrayList<ArrayList<Edge>>(); for(int i = 0; i <= n; i++) { /** i 정점에 대한 간선들 초기화 :: 이중 어레이이스트 **/ list.add(new ArrayList<Edge>()); } for(int i = 0; i < m; i++) { st = new StringTokenizer(br.readLine()); int a = Integer.parseInt(st.nextToken()); int b = Integer.parseInt(st.nextToken()); int cost = Integer.parseInt(st.nextToken()); /** a 와 b 가 cost 로 연결된 상태 **/ list.get(a).add(new Edge(b, cost)); list.get(b).add(new Edge(a, cost)); } int value = process(list); bw.write(value + "\n"); bw.flush(); bw.close(); br.close(); } private static int process(ArrayList<ArrayList<Edge>> list) { int minSumCost = 0; int edgeCount = 0; /** 1번 정점을 시작으로 잡는다. **/ int vertex = 1; visited[vertex] = 1; /** 1번 정점을 기점으로 갈 수 있는 간선의 비용을 초기화 **/ for(int eIndex = 0; eIndex < list.get(vertex).size(); eIndex++) { Edge edge = list.get(vertex).get(eIndex); distance[edge.e] = edge.cost; } /** MST :: 간선의 개수는 정점 개수 - 1 **/ while(edgeCount != n - 1) { for(int eIndex = 0; eIndex < list.get(vertex).size(); eIndex++) { Edge edge = list.get(vertex).get(eIndex); /** 미방문 **/ if(visited[edge.e] == 1) { continue; } /** edge.e 로 가는 비용의 값 **/ if(distance[edge.e] < edge.cost) { continue; } /** 현재 내가 탐색한 정점에서 갈 수 있는 비용 수정 **/ distance[edge.e] = edge.cost; } int tempVertex = 0; int min = Integer.MAX_VALUE; /** 미방문 + 가장 낮은 비용의 거리로 vertex 초기화 **/ for(int start = 1; start < distance.length; start++) { if(visited[start] == 1) { continue; } if(min > distance[start]) { min = distance[start]; tempVertex = start; } } /** vertex 와 tempVertex 를 잇는 비용 값 누적 **/ minSumCost += distance[tempVertex]; /** tempVertex 방문 **/ visited[tempVertex] = 1; /** vertex 초기화 **/ vertex = tempVertex; /** 정점과 정점을 이어주는 간선 하나 추가 **/ edgeCount += 1; } return minSumCost; } } class Edge{ public int e; public int cost; public Edge(int e, int cost) { this.e = e; this.cost = cost; } } | cs |
'Problem Solving & Algorithm > BOJ ' 카테고리의 다른 글
20190401 1197번 : 최소 스패닝 트리 (0) | 2019.04.02 |
---|---|
20190331 14500번 : 테트로미노 (0) | 2019.03.31 |
20190301 10819번 : 차이를 최대로 (수정 : 20190309) (0) | 2019.03.01 |
20190301 11722번 : 가장 긴 감소하는 부분 수열 (0) | 2019.03.01 |
20190224 14502번 : 연구소 (0) | 2019.02.24 |