코딩테스트/백준

[Java] 백준 1238번 : 파티

이덩우 2023. 12. 20. 01:58

문제소개

 

해결과정

다익스트라 문제이다.

1 ~ N번 노드가 존재하며, 특정 X 노드를 지정해 다른 노드에 있는 사람들은 모두 X 노드로 왔다가 다시 제자리로 돌아가야한다.

이 때, 노드 사이에는 가중치가 있는 간선이 존재한다. *단방향 간선이기 때문에 가는 길과 오는 길이 다를 수 있다.*

X번 노드를 제외한 다른 모든 노드에서 X 노드를 방문했다가 다시 돌아올 때 최단 거리를 구해야하고, 모든 노드 중 최단 거리가 가장 큰 노드를 찾아내면 된다.

 

문제 풀이의 핵심은 다익스트라를 총 2번 활용해 풀이해내는 것이다. (1 : 임의의 노드 -> X 노드, 2 : X 노드 -> 임의의 노드)

X 노드에서 각 노드로 가는 최단거리는 X 노드를 시작으로 하는 다익스트라를 구성하면 된다.

 

문제는 반대 방향에서 발생한다.

임의의 노드에서 X 노드로 가는 최단거리를 구하려면 임의의 노드를 시작 지점으로 하는 다익스트라를 N - 1번 돌리면 될까?

물론 이론상으로는 정답을 구할 수 있을 것이다. 하지만 주어진 노드의 크기와 간선을 고려한다면 시간초과가 발생할 가능성이 있기에 

추가적으로 단 한번의 다익스트라를 통해 임의의 노드에서 X 노드로 최단거리를 모두 구할 수 있어야한다.

 

솔루션은 간단했다. 최초 주어진 간선의 정보 자체가 단방향이기 때문에, *방향을 바꾼 그래프를 추가로 만들어놓으면 된다.*

쉽게 생각해 주어진 간선을 그대로 표현한 정방향 그래프와 방향을 바꾼 역방향 그래프, 총 두 개의 그래프를 생성한다.

 

역방향 그래프를 통해, X 노드를 시작으로하는 다익스트라를 돌린다면 임의의 노드에서 X 노드로 가는 최단거리를 단 한번의 다익스트라 알고리즘을 통해 모두 구할 수 있다!

 

솔루션

public class Main {

    static ArrayList<Node>[] posGraph, nagGraph;
    static int[] posDist, nagDist, result;
    static int N, M, X;

    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());
        X = Integer.parseInt(st.nextToken());

        posGraph = new ArrayList[N + 1];
        nagGraph = new ArrayList[N + 1];
        posDist = new int[N + 1];
        nagDist = new int[N + 1];
        result = new int[N + 1];
        Arrays.fill(posDist, Integer.MAX_VALUE);
        Arrays.fill(nagDist, Integer.MAX_VALUE);

        for (int i = 0; i <= N; i++) {
            posGraph[i] = new ArrayList<>();
            nagGraph[i] = new ArrayList<>();
        }

        for (int i = 0; i < M; i++) {
            st = new StringTokenizer(br.readLine());
            int start = Integer.parseInt(st.nextToken());
            int end = Integer.parseInt(st.nextToken());
            int cost = Integer.parseInt(st.nextToken());

            posGraph[start].add(new Node(end, cost));
            nagGraph[end].add(new Node(start, cost));
        }

        dijkstra(posDist, posGraph);
        dijkstra(nagDist, nagGraph);

        for (int i = 0; i <= N; i++) {
            result[i] = posDist[i] + nagDist[i];
        }

        int maxValue = Arrays.stream(result)
                .max()
                .orElse(-1);
        System.out.println(maxValue);
    }

    static void dijkstra(int[] dist, ArrayList<Node>[] graph) {
        PriorityQueue<Node> pq = new PriorityQueue<>((n1, n2) -> Integer.compare(n1.cost, n2.cost));
        boolean[] visited = new boolean[N + 1];

        pq.add(new Node(X, 0));
        dist[X] = 0;

        while (!pq.isEmpty()) {
            Node poll = pq.poll();

            if (visited[poll.vertex]) continue;
            visited[poll.vertex] = true;

            for (Node node : graph[poll.vertex]) {
                if (dist[node.vertex] > poll.cost + node.cost) {
                    dist[node.vertex] = poll.cost + node.cost;
                    pq.add(new Node(node.vertex, dist[node.vertex]));
                }
            }
        }
    }

    static class Node {
        int vertex;
        int cost;

        public Node(int vertex, int cost) {
            this.vertex = vertex;
            this.cost = cost;
        }
    }
}