알고리즘

백준 1753번 최단경로

창따오 2023. 12. 29. 09:56
728x90

출처 : https://www.acmicpc.net/problem/1753

 

1753번: 최단경로

첫째 줄에 정점의 개수 V와 간선의 개수 E가 주어진다. (1 ≤ V ≤ 20,000, 1 ≤ E ≤ 300,000) 모든 정점에는 1부터 V까지 번호가 매겨져 있다고 가정한다. 둘째 줄에는 시작 정점의 번호 K(1 ≤ K ≤ V)가

www.acmicpc.net

 

최단경로 문제는 솔직히 그렇게 어렵지 않다. 하지만 최단경로를 이용하여 응용할 문제가 많아서 꼭 알아두어야 할 알고리즘이다. 

이문제의 경우, 전형적인 최단경로 문제인데, 시작점을 기준으로 단방향으로 연결돼있는 노드들의 가중치 값을 비교하며 최단거리를 갱신해 해 가는 과정이다.

 

출처 : 나무위키

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class Baek1753 {
    static int dist[];
    static List<List<Node>> graph = new ArrayList<>();

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int v = Integer.parseInt(st.nextToken());
        int e = Integer.parseInt(st.nextToken());
        int start = Integer.parseInt(br.readLine());
        dist = new int[v + 1];
        //graph 초기화 해주기
        for (int i = 0; i <= v; i++) { // 0인덱스는 사용 X Node num과 맞춰주기 위함
            graph.add(new ArrayList<>());
            dist[i] = Integer.MAX_VALUE;
        }
        for (int i = 0; i < e; i++) {
            st = new StringTokenizer(br.readLine());
            int from = Integer.parseInt(st.nextToken());
            int to = Integer.parseInt(st.nextToken());
            int weight = Integer.parseInt(st.nextToken());
            graph.get(from).add(new Node(to, weight));
        }
        dijkstra(start);
        StringBuilder sb = new StringBuilder();
        for (int i = 1; i <= v; i++) {
            if (dist[i] == Integer.MAX_VALUE) {
                sb.append("INF").append("\n");
            }else{
                sb.append(dist[i]).append("\n");
            }
        }
        System.out.println(sb.toString());
    }

    //최단 경로 문제
    static void dijkstra(int start){
        dist[start] = 0; // 시작점은 0;
        PriorityQueue<Node> pq = new PriorityQueue<>();
        pq.offer(new Node(start, 0));
        while (!pq.isEmpty()) {
            Node curNode = pq.poll();
            List<Node> children = graph.get(curNode.num);
            for(Node child: children){
                if(dist[child.num]> curNode.weight+child.weight){
                    dist[child.num] = curNode.weight + child.weight;
                    pq.offer(new Node(child.num, dist[child.num]));
                }
            }
        }



    }
    static class Node implements Comparable<Node>{
        private int num;
        private int weight;

        public Node(int num, int weight){
            this.num = num;
            this.weight = weight;
        }

        @Override
        public int compareTo(Node o) {
            return this.weight - o.weight;
        }
    }
}

 

소스코드에 세세하게 주석을 달지 않았지만, 주석을 보지않고 이해하면 더 이해가 깊어질 거라 예상된다? 큰 틀에서 보자면 PriorityQueue를 사용하여 가중치를 기준으로 더 작은 가중치로 시작노드를 기준으로 계속 갱신해나간다. dist[]의 경우, 특정 노드까지의 최단거리 값이 담긴다. 이것이 핵심이다.