출처 : www.acmicpc.net/problem/1197
문제
그래프가 주어졌을 때, 그 그래프의 최소 스패닝 트리를 구하는 프로그램을 작성하시오.
최소 스패닝 트리는, 주어진 그래프의 모든 정점들을 연결하는 부분 그래프 중에서 그 가중치의 합이 최소인 트리를 말한다.
입력
첫째 줄에 정점의 개수 V(1 ≤ V ≤ 10,000)와 간선의 개수 E(1 ≤ E ≤ 100,000)가 주어진다. 다음 E개의 줄에는 각 간선에 대한 정보를 나타내는 세 정수 A, B, C가 주어진다. 이는 A번 정점과 B번 정점이 가중치 C인 간선으로 연결되어 있다는 의미이다. C는 음수일 수도 있으며, 절댓값이 1,000,000을 넘지 않는다.
그래프의 정점은 1번부터 V번까지 번호가 매겨져 있고, 임의의 두 정점 사이에 경로가 있다. 최소 스패닝 트리의 가중치가 -2,147,483,648보다 크거나 같고, 2,147,483,647보다 작거나 같은 데이터만 입력으로 주어진다.
출력
첫째 줄에 최소 스패닝 트리의 가중치를 출력한다.
풀이
1. MST를 구하는 문제는, 크루스칼과 프림알고리즘이 대표적이다. 그 중 프림 알고리즘 공부를 위해 프림 알고리즘을 택했다.
어려웠던 점, 알게된 것
1. 우선순위 큐에서 꺼내는 과정에서 = 그것은 곧 방문을 의미한다고 생각했다. 따라서, 방문처리는 따로하지 않았다.
2. 하지만, 방문처리를 반드시 해줘야 한다.
3. 왜? 우선순위 큐에는 이전 방문한 노드들을 포함한 인접한 노드들이 모두 들어 있기 때문에 한 참 지나쳐온 가중치가 낮은 노드가 꺼내질 수 있다.
관련 코드
while(!pq.isEmpty()) {
// 꺼내고
node cur = pq.poll();
// 그굿이 방문한 곳이라면 패스 ! ** 이부분이 꼭 있어야한다. why? 큐를 꺼내는과정에서 예전에 넣어놨던 친구들이 나올 수 가 있잖아 !
if( visited[cur.vertex]) continue;
// 방문처리
visited[cur.vertex] = true;
// 방문했으니까, 가중치 더해주기
answer += cur.weight;
for ( node next : arr[cur.vertex]) {
if ( !visited[next.vertex]) {
pq.add(next);
}
}
if ( ++ count == Vertex )break;
최종 정답 코드
package 알고리즘공부하기;
import java.io.*;
import java.util.*;
public class 프림알고리즘_1197 {
static int Vertex, Edge;
static int start = 1;
static ArrayList<node>[] arr;
static PriorityQueue<node> pq = new PriorityQueue<>();
static boolean[] visited;
static long answer =0;
public static class node implements Comparable<node>{
int vertex;
int weight;
public node(int vertex, int weight) {
this.vertex = vertex;
this.weight = weight;
}
@Override
public int compareTo(node o) {
return this.weight - o.weight;
}
}
public static void main(String[] args) throws IOException {
Scanner sc =new Scanner(System.in);
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
st = new StringTokenizer(br.readLine()," ");
Vertex = Integer.parseInt(st.nextToken());
Edge = Integer.parseInt(st.nextToken());
visited = new boolean[Vertex+1]; // 각 정점은 1부터 시작한다.
arr = new ArrayList[Vertex+1];
for ( int i=0; i<=Vertex; i++) {
arr[i] = new ArrayList<>();
}
// 정점간 연결
for( int i=0; i<Edge; i++) {
st = new StringTokenizer(br.readLine(), " ");
int from = Integer.parseInt(st.nextToken());
int to = Integer.parseInt(st.nextToken());
int weight = Integer.parseInt(st.nextToken());
arr[from].add(new node(to,weight));
arr[to].add(new node(from,weight));
}
// 시작점은 아무곳이나 상관 없지만, 1번 부터 시작하자.
prim();
System.out.println(answer);
}
private static void prim() {
// 1번부터 시작해서 연결되어 있는 곳 모두 탐색하자.
pq.add(new node(start,0));
int count =0;
while(!pq.isEmpty()) {
// 꺼내고
node cur = pq.poll();
// 그굿이 방문한 곳이라면 패스 ! ** 이부분이 꼭 있어야한다. why? 큐를 꺼내는과정에서 예전에 넣어놨던 친구들이 나올 수 가 있잖아 !
if( visited[cur.vertex]) continue;
// 방문처리
visited[cur.vertex] = true;
// 방문했으니까, 가중치 더해주기
answer += cur.weight;
for ( node next : arr[cur.vertex]) {
if ( !visited[next.vertex]) {
pq.add(next);
}
}
if ( ++ count == Vertex )break;
}
}
}
'알고리즘' 카테고리의 다른 글
[프로그래머스] 문자열 다루기 기본 [JAVA] (0) | 2020.10.17 |
---|---|
[프로그래머스] 두 개 뽑아서 더하기 [JAVA] (0) | 2020.10.17 |
[백준] 행성 연결 16398 [JAVA] (0) | 2020.10.17 |
[백준] 떡 돌리기 2007 [JAVA] (0) | 2020.10.16 |
[백준] 치킨 배달 15686 [JAVA] (0) | 2020.10.07 |