코린이의 소소한 공부노트

[백준 온라인 저지] 1948. 임계경로 본문

코딩테스트 풀이/JAVA

[백준 온라인 저지] 1948. 임계경로

무지맘 2023. 6. 20. 13:51

임계 경로란 어떤 일을 완료하기까지 걸리는 여러 가지 경로 중 가장 긴 시간이 걸리는 경로를 말한다.

 

월드 나라는 모든 도로가 일방통행인 도로이고, 싸이클이 없다. 그런데 어떤 무수히 많은 사람들이 월드 나라의 지도를 그리기 위해서, 어떤 시작 도시로부터 도착 도시까지 출발을 하여 가능한 모든 경로를 탐색한다고 한다.

이 지도를 그리는 사람들은 사이가 너무 좋아서 지도를 그리는 일을 다 마치고 도착 도시에서 모두 다 만나기로 하였다. 그렇다고 하였을 때 이들이 만나는 시간은 출발 도시로부터 출발한 후 최소 몇 시간 후에 만날 수 있는가? , 마지막에 도착하는 사람까지 도착을 하는 시간을 의미한다.

어떤 사람은 이 시간에 만나기 위하여 1분도 쉬지 않고 달려야 한다. 이런 사람들이 지나는 도로의 수를 카운트 하여라.

출발 도시는 들어오는 도로가 0개이고, 도착 도시는 나가는 도로가 0개이다.

 

1. 입력

- 첫째 줄에 도시의 개수 n(1 n 10,000)이 주어지고 둘째 줄에는 도로의 개수 m(1 m 100,000)이 주어진다.

- 셋째 줄부터 m+2줄까지 다음과 같은 도로의 정보가 주어진다. 처음에는 도로의 출발 도시의 번호가 주어지고 그 다음에는 도착 도시의 번호, 그리고 마지막에는 이 도로를 지나는데 걸리는 시간이 주어진다. 도로를 지나가는 시간은 10,000보다 작거나 같은 자연수이다.

- m+3째 줄에는 지도를 그리는 사람들이 출발하는 출발 도시와 도착 도시가 주어진다.

- 모든 도시는 출발 도시로부터 도달이 가능하고, 모든 도시로부터 도착 도시에 도달이 가능하다.

 

2. 출력

- 첫째 줄에는 이들이 만나는 시간을, 둘째 줄에는 1분도 쉬지 않고 달려야 하는 도로의 수가 몇 개인지 출력하여라.

 

3. 예제

 

4. 코드

import java.util.*;
import java.io.*;
class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        int n = Integer.valueOf(br.readLine()); // 도시의 수
        int m = Integer.valueOf(br.readLine()); // 도로의 수
        int[] indegree = new int[n+1]; // i번째 도시에 방문 전 먼저 가야 하는 도시의 수
        Queue<Integer> q = new LinkedList<>(); // 정렬에 필요한 큐
        int[] result = new int[n+1]; // i번째 도시에 방문하는 데 걸리는 총 시간
        
        // 출발 -> 도착 (for 임계경로 계산)
        List<List<Integer>> edge = new ArrayList<List<Integer>>(); // 간선의 정보(방문도시)
        List<List<Integer>> time = new ArrayList<List<Integer>>(); // 간선의 정보(시간)
        
        // 도착 -> 출발 (for 임계경로의 도로의 수 파악)
        List<List<Integer>> edgeR = new ArrayList<List<Integer>>(); // 간선의 정보(방문도시)
        List<List<Integer>> timeR = new ArrayList<List<Integer>>(); // 간선의 정보(시간)
        
        for(int i=0 ; i<=n ; i++){ // 편의를 위해 0번째는 사용하지 않을 예정
            edge.add(new ArrayList<>()); // i번째 도시에 방문 후 edge.get(i)에 방문
            time.add(new ArrayList<>()); // i번째 도시에서 edge.get(i)에 가는 데 걸리는 시간
            edgeR.add(new ArrayList<>());
            timeR.add(new ArrayList<>());
        }
        
        for(int i=1 ; i<=m ; i++){ // m개의 도로에 대한 정보 처리
            StringTokenizer token = new StringTokenizer(br.readLine());
            int c1 = Integer.valueOf(token.nextToken()); // 도로의 출발 도시의 번호
            int c2 = Integer.valueOf(token.nextToken()); // 도로의 도착 도시의 번호
            int t = Integer.valueOf(token.nextToken()); // 걸린 시간
            edge.get(c1).add(c2);
            time.get(c1).add(t);
            edgeR.get(c2).add(c1);
            timeR.get(c2).add(t);
            indegree[c2]++;
        }
        StringTokenizer token = new StringTokenizer(br.readLine());
        int start = Integer.valueOf(token.nextToken()); // 출발 도시의 번호
        int end = Integer.valueOf(token.nextToken()); // 도착 도시의 번호
        
        q.add(start); // 출발 도시부터 방문하면서 총 소요시간 계산
        while(!q.isEmpty()) {
            int cur = q.remove();
            for(int i=0 ; i<edge.get(cur).size() ; i++){
                int next = edge.get(cur).get(i);
                result[next] = Math.max(result[next], result[cur]+time.get(cur).get(i));
                if(--indegree[next]==0) q.add(next);
            }      
        }
        
        int count = 0; // 임계 경로에 있는 도로의 수
        q.add(end); // 도착 도시부터 역으로 가면서 카운팅
        boolean[] visit = new boolean[n+1]; // 계산하면서 방문했다면 true
        while(!q.isEmpty()){
            int cur = q.remove();
            for(int i=0 ; i<edgeR.get(cur).size() ; i++){
                int prev = edgeR.get(cur).get(i);
                if(result[cur]-result[prev] == timeR.get(cur).get(i)){
                    count++;
                    if(!visit[prev]) {
                        q.add(prev);
                        visit[prev] = true;
                    }
                }                
            }
        }
        
        bw.write(result[end]+"\n"+count);
        bw.flush(); bw.close();
    }
}