알고리즘/Dijkstra
[Java] 백준 11779번 최소비용 구하기 풀이
helloJosh
2024. 8. 4. 15:55
✅문제
✅문제 풀이
어떤 출발 도시에서 도착 도시까지의 최단 비용을 구하고 거쳐가는 경로와 지나는 도시의 개수를 출력하는 문제이다. 경로에 비용이 있기때문에 다익스트라 알고리즘을 사용해야한다.
간단하게 다익스트라 알고리즘을 소개하자면 어떤 정점에서 각 정점까지의 최단거리인 표를 만들고, 정점 마다 각 정점까지 거리를 계산해 그 어떤 정점에서 각 정점까지의 최단 거리를 계속해서 업데이트해 최단 거리를 알아내는 알고리즘이다.
짧은 예시 하나로 설명하겠습니다.
이러한 그래프가 있다고 예시를 들고, 시작점을 1이라고 하자.
그럼 처음 초기화 된 표는 다음과 같고
정점 | 1 | 2 | 3 | 4 | 5 |
경로값 | 무한 | 무한 | 무한 | 무한 | 무한 |
1부터 탐색을 시작하게되면 아래와 같은 표로 값을 넣는다. 정점 5로가는 경로는 현재로서는 아예 모르기때문에 무한이나 Integer.MAX_VALUE로 들어가게 되고 2,3,4는 1과 인접해있기때문에 그 비용이 들어가게된다.
정점 | 1 | 2 | 3 | 4 | 5 |
경로값 | 0 | 3 | 6 | 7 | 무한 |
1의 탐색이 끝났으니 1을 탐색 끝으로 체크해놓고 다음 정점 2에서 탐색한다.
이때 1 -> 3 보다 1 -> 2 -> 3가는 경로의 값이 더 적어서 아래 표가 업데이트 됩니다.
정점 | 1 | 2 | 3 | 4 | 5 |
경로값 | 0 | 3 | 4 | 7 | 무한 |
이러한 방식으로 모든 정점을 돌면서 정점 1에서 각 정점을 가는 최소 비용을 구할 수 있습니다.
여기에 PriorityQueue를 쓰는 이유는 각 정점을 둘러볼떄 최소 비용을 먼저 찾기 때문에 알고리즘 성능을 좀 더 높일 수있습니다. 일반 Queue를 사용하면 비용이 높은데도 먼저 들어왔단 이유로 둘러보지 않아도될 값을 둘러보게되기 때문에 PriorityQueue를 사용합니다.
✅Code
package classthree;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class Beak11779 {
public static class Node implements Comparable<Node>{
int e;
int cost;
public Node(int e, int cost) {
this.e = e;
this.cost = cost;
}
@Override
public int compareTo(Node o) {
return this.cost - o.cost;
}
}
public static class Matrix {
List<List<Node>> arrays;
public Matrix(int size) {
arrays = new ArrayList<>();
for (int i = 0; i < size; i++) {
List<Node> rows = new ArrayList<>();
arrays.add(rows);
}
}
public void addNode(int from, int to, int cost){
arrays.get(from).add(new Node(to, cost));
}
}
public static class MatrixService {
private Matrix matrix;
private List<Integer> distances;
private List<Integer> routes;
private List<Boolean> checks;
public MatrixService(Matrix matrix) {
this.matrix = matrix;
distances = new ArrayList<>(Collections.nCopies(matrix.arrays.size(), Integer.MAX_VALUE));
routes = new ArrayList<>(Collections.nCopies(matrix.arrays.size(), -1));
checks = new ArrayList<>(Collections.nCopies(matrix.arrays.size(), false));
}
public void findShortestDirection(int from){
PriorityQueue<Node> queue = new PriorityQueue<>();
queue.add(new Node(from, 0));
distances.set(from, 0);
routes.set(from, from);
while (!queue.isEmpty()) {
Node cur = queue.remove();
if (!checks.get(cur.e)) {
checks.set(cur.e, true);
} else {
continue;
}
for (Node next : matrix.arrays.get(cur.e)) {
if (distances.get(next.e) > distances.get(cur.e) + next.cost) {
distances.set(next.e, distances.get(cur.e) + next.cost);
queue.add(new Node(next.e, distances.get(next.e)));
routes.set(next.e, cur.e);
}
}
}
}
public List<Integer> getShortestPath(int to, int from) {
List<Integer> path = new ArrayList<>();
for (int at = to; at != from; at = routes.get(at)) {
path.add(at);
}
path.add(from);
Collections.reverse(path);
return path;
}
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
int n = Integer.parseInt(br.readLine());
int m = Integer.parseInt(br.readLine());
Matrix matrix = new Matrix(n);
for (int i = 0; i < m; i++) {
st = new StringTokenizer(br.readLine());
matrix.addNode(
Integer.parseInt(st.nextToken()) - 1,
Integer.parseInt(st.nextToken()) - 1,
Integer.parseInt(st.nextToken()));
}
MatrixService matrixService = new MatrixService(matrix);
st = new StringTokenizer(br.readLine());
int from = Integer.parseInt(st.nextToken()) - 1;
int to = Integer.parseInt(st.nextToken()) - 1;
matrixService.findShortestDirection(from);
System.out.println(matrixService.distances.get(to));
List<Integer> path = matrixService.getShortestPath(to, from);
System.out.println(path.size());
for (int num : path) {
System.out.print(num + 1 + " ");
}
}
}