알고리즘/[ Baekjoon ]

[ BOJ ][JAVA][1719] 택배

kim.svadoz 2021. 10. 26. 16:59
728x90
반응형

https://www.acmicpc.net/problem/1719

 

1719번: 택배

명우기업은 2008년부터 택배 사업을 새로이 시작하기로 하였다. 우선 택배 화물을 모아서 처리하는 집하장을 몇 개 마련했지만, 택배 화물이 각 집하장들 사이를 오갈 때 어떤 경로를 거쳐야 하

www.acmicpc.net

시간 제한 메모리 제한 제출 정답 맞은 사람 정답 비율
2 초 128 MB 2811 1517 996 56.208%

문제

명우기업은 2008년부터 택배 사업을 새로이 시작하기로 하였다. 우선 택배 화물을 모아서 처리하는 집하장을 몇 개 마련했지만, 택배 화물이 각 집하장들 사이를 오갈 때 어떤 경로를 거쳐야 하는지 결정하지 못했다. 어떤 경로를 거칠지 정해서, 이를 경로표로 정리하는 것이 여러분이 할 일이다.

img

예시된 그래프에서 굵게 표시된 1, 2, 3, 4, 5, 6은 집하장을 나타낸다. 정점간의 간선은 두 집하장간에 화물 이동이 가능함을 나타내며, 가중치는 이동에 걸리는 시간이다. 이로부터 얻어내야 하는 경로표는 다음과 같다.

img

경로표는 한 집하장에서 다른 집하장으로 최단경로로 화물을 이동시키기 위해 가장 먼저 거쳐야 하는 집하장을 나타낸 것이다. 예를 들어 4행 5열의 6은 4번 집하장에서 5번 집하장으로 최단 경로를 통해 가기 위해서는 제일 먼저 6번 집하장으로 이동해야 한다는 의미이다.

이와 같은 경로표를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 두 수 n과 m이 빈 칸을 사이에 두고 순서대로 주어진다. n은 집하장의 개수로 200이하의 자연수, m은 집하장간 경로의 개수로 10000이하의 자연수이다. 이어서 한 줄에 하나씩 집하장간 경로가 주어지는데, 두 집하장의 번호와 그 사이를 오가는데 필요한 시간이 순서대로 주어진다. 집하장의 번호들과 경로의 소요시간은 모두 1000이하의 자연수이다.

출력

예시된 것과 같은 형식의 경로표를 출력한다.

예제 입력 1

6 10
1 2 2
1 3 1
2 4 5
2 5 3
2 6 7
3 4 4
3 5 6
3 6 7
4 6 4
5 6 2

예제 출력 1

- 2 3 3 2 2
1 - 1 4 5 5
1 1 - 4 5 6
3 2 3 - 6 6
2 2 3 6 - 6
5 5 3 4 5 -

코드

/**
 * BOJ 1719 택배 : Gold 4
 * 다익스트라, 역추적, 플로이드와샬
 */
import java.io.*;
import java.util.*;

public class p1719 {
    static class Edge implements Comparable<Edge> {
        int to, cost;
        public Edge(int to, int cost) {
            this.to = to;
            this.cost = cost;
        }

        public int compareTo(Edge o) {
            return cost - o.cost;
        }
    }
    static int n, m;
    static List<List<Edge>> list;
    static int[] path, dist;
    static boolean[] visited;
    static final int INF = 987654321;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        n = Integer.parseInt(st.nextToken());
        m = Integer.parseInt(st.nextToken());

        list = new ArrayList<>();
        for (int i = 0; i <= n; i++) {
            list.add(new ArrayList<>());
        }

        for (int i = 0; i < m; i++) {
            st = new StringTokenizer(br.readLine());
            int u = Integer.parseInt(st.nextToken());
            int v = Integer.parseInt(st.nextToken());
            int cost = Integer.parseInt(st.nextToken());
            list.get(u).add(new Edge(v, cost));
            list.get(v).add(new Edge(u, cost));
        }

        for  (int i = 1; i <= n; i++) {
            path = new int[n + 1];
            dist = new int[n + 1];
            visited = new boolean[n + 1];
            Arrays.fill(dist, INF);
            dijkstra(i);
        }
    }

    /**
     * 한 정점에서의 최단거리가 모두 다르므로 각 정점마다 다익스트라를 돌려준다. -> 따라서 플로이드도 가능하다
     * @param start
     */
    static void dijkstra(int start) {
        PriorityQueue<Edge> pq = new PriorityQueue<>();
        pq.add(new Edge(start, 0));
        dist[start] = 0;

        while (!pq.isEmpty()) {
            Edge cur = pq.poll();
            if (visited[cur.to]) continue;
            visited[cur.to] = true;

            for (Edge adj : list.get(cur.to)) {
                if (visited[adj.to]) continue;

                if (dist[adj.to] > dist[cur.to] + adj.cost) {
                    // 경로를 역추적하기 위해 현재 인덱스에 직전 노드를 저장한다.
                    // ex. path[3] = 1 ::: 3번 노드를 오기 바로 직전노드는 1번노드
                    path[adj.to] = cur.to;
                    dist[adj.to] = dist[cur.to] + adj.cost;
                    pq.add(new Edge(adj.to, dist[adj.to]));
                }
            }
        }

        // dfs로 경로를 역추적해야 한다. (find method)
        StringBuilder sb = new StringBuilder();
        for (int i = 1; i <= n; i++) {
            if (i == start) sb.append("-").append(" ");
            else sb.append(find(i, start)).append(" ");
        }
        System.out.println(sb.toString());
    }

    /**
     * 
     * @param x 현재 위치
     * @param start 최단거리 그래프의 맨 처음 시작 노드
     * @return
     */
    static int find(int x, int start) {
        if (path[x] == start) return x;
        return find(path[x], start);
    }
}
728x90
반응형