DY N DY
알고리즘 최소비용신장트리(JAVA) 본문
1060 : 최소비용신장트리
제한시간: 1Sec 메모리제한: 32mb
해결횟수: 860회 시도횟수: 2796회
정보올림피아드 공부를 더욱 효율적으로 할 수 있도록 전국에 흩어져 있는 정올 학원들을 네트워크로 연결하려고 한다.그러나 모든 학원들을 네트워크로 연결하려면 너무 많은 비용이 필요하기 때문에 정올에서는 학원들을 연결하는 비용을 최소가 되게 하려고 한다. 학원들은연결되어 있는 다른 학원의 회선을 공유할 수 있다.
아래 그림과 같이 학원 사이를 연결하기 위한 비용이 주어지면 모든 학원을 연결하기 위한 최소의 비용을 구하는 프로그램을 작성하라.
[Copy]
| [Copy]
|
- import java.util.Scanner;
- public class Main
- {
- private static Scanner sc;
- int N = sc.nextInt();
- int [][] map = new int[N][N];
- int len = 0;
- int [] label = new int[N];
- Vertex [] points = new Vertex[5050];
- for(int i = 0 ; i < N; ++i){
- label[i] = i;
- for(int j = 0; j < N; ++j){
- map[i][j] = sc.nextInt();
- if(i < j){
- points[len++] = new Vertex(i, j, map[i][j]);
- }
- }
- }
- // 1. 정렬
- quickSort(points, 0, len-1);
- // 2. 어사이클
- int nodes = 0, index = 0;
- int cost = 0, tmp = 0;
- while(nodes < N-1)
- {
- if(label[points[index].x] != label[points[index].y])
- {
- tmp = label[points[index].y];
- for(int i = 0 ; i < N; ++i){
- if(tmp == label[i])
- label[i] = label[points[index].x];
- }
- cost += points[index].cost;
- nodes++;
- }
- index++;
- }
- }
- public static void quickSort(Vertex[] array, int s, int e) {
- if(s >= e){
- return;
- }
- int i = s + 1;
- int j = e;
- Vertex pivot = array[s];
- while (i <= j) {
- while (i <= e && array[i].cost <= pivot.cost)
- i++;
- while (s + 1 <= j && pivot.cost <= array[j].cost)
- j--;
- if (i <= j) {
- Vertex temp = array[i];
- array[i] = array[j];
- array[j] = temp;
- } else {
- array[s] = array[j];
- array[j] = pivot;
- }
- }
- quickSort(array, s, j - 1 );
- quickSort(array, j + 1, e );
- }
- }
- class Vertex
- {
- public int x;
- public int y;
- public int cost;
- Vertex(int x, int y, int cost)
- {
- this.x = x;
- this.y = y;
- this.cost = cost;
- }
- }
그리디 알고리즘으로 풀 수 있는 대표적인 문제.
특히 최소비용신장트리는 유명한 문제로 이를 해결하기 위한 알고리즘은 유명한 두 알고리즘이 있다.
1. 크루스칼(Kruskal) 알고리즘
2. 프림(Prim) 알고리즘
두 알고리즘은 보통 방향성을 가지지 않는 그래프에서 최소비용 혹은 최대효율을 만드는 신장트리(spanning tree - 모든 vertex를 포함하는 부분 집합)
에서 사용되고 다익스트라(Dijkstra) 알고리즘은 방향성을 가지는 그래프에서 특정 vertex에서 다른 vertex로 가는 최단경로를 푸는 문제에 주로 사용된다.
크루스칼 알고리즘은 쉽게 설명하면 다음과 같다.
1. 모든 edge를 가중치 별로 정렬한다.
방향성을 가지지 않기 때문에 입력받은 map에서 중복되지 않는 edge만을 points 배열에 저장하였다.
정렬은 Java내의 정렬을 사용해도 되나 quick sort를 구현해보았다.
2. 가장 작은 가중치를 가진 edge을 선택한다.
3. 선택한 edge가 cycle을 만들면 그 edge는 버린다.
이때 구현을 위해 각각의 점에 label을 붙였고, 연결된 vertex끼리는 같은 label을 가져가도록 하였다.
모든 vertex가 동일한 label을 가지고 있다면 모든 vertex는 연결된 것이다.
4. 2, 3번을 반복하며 N개의 vertex가 있을 때 N-1개의 edge가 선택되면 알고리즘이 종료된다. (N개의 vertex는 N-1개의 edge로 연결이 가능하다.)
'PARK > ALGORITHM' 카테고리의 다른 글
실력키우기 이진탐색(JAVA) (0) | 2016.04.26 |
---|---|
실력키우기 약수(C++) (0) | 2016.04.20 |
알고리즘 지하철(C++) (0) | 2016.04.17 |
실력키우기 문자삼각형2(C++) (0) | 2016.04.17 |
실력키우기 곱셈(JAVA) (0) | 2016.04.14 |