새소식

PS/백준

[백준/1948] 임계경로 (Python)

  • -

Problem : https://www.acmicpc.net/problem/1948

 

1948번: 임계경로

첫째 줄에 도시의 개수 n(1 ≤ n ≤ 10,000)이 주어지고 둘째 줄에는 도로의 개수 m(1 ≤ m ≤ 100,000)이 주어진다. 그리고 셋째 줄부터 m+2줄까지 다음과 같은 도로의 정보가 주어진다. 처음에는 도로의

www.acmicpc.net

 

Difficulty : Platinum 5

 

Status : Solved

 

Time : 00:13:58

 


 

문제 설명

 

더보기

 

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

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

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

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

 

 

입력 및 출력

 

더보기

입력

 

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

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

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

 

출력

 

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

 

입력 예시

 

7
9
1 2 4
1 3 2
1 4 3
2 6 3
2 7 5
3 5 1
4 6 4
5 6 2
6 7 5
1 7

 

출력 예시

 

12
5

 

 


 

풀이

 

어..? 이렇게 푸는 게 아닌데...? 싶다가 어찌저찌 풀려버린 문제.

 

지금의 풀이는 최장 거리를 탐색해야 하므로 단순 dfs를 통한 최장 거리 탐색을 베이스로 탐색하고, 이후 백트래킹으로 최장 거리에 포함되는 중간 간선의 수를 반환하는 방식이다. 파이썬은 시간 초과, 파이파이로 간신히 통과하는 코드이다.

 

풀이 후에 찝찝해서 나름 검색해 본 결과, 위상정렬을 이용해서 풀이가 가능하다고 한다. 즉 어떤 노드에 도달했을 때 최장 경로임이 만족되려면(임계 경로), 그 노드로 향하는 모든 간선을 먼저 탐색하였음이 보장되어야 한다. (사이클이 없음이 보장되므로 먼저 생각했어야 했다) 이 경우 각 노드의 삽입 횟수를 회긱적으로 줄일 수 있으니 매우 효율적으로 연산할 수 있게 된다.

 

 

풀이 코드 (pypy3)

from collections import defaultdict, deque
import sys
input = sys.stdin.readline
MAX = float('inf')

N = int(input())
M = int(input())

edge_dict = defaultdict(list)
rev_edge_dict = defaultdict(list)

for _ in range(M) :
  a, b, c = map(int, input().split())
  edge_dict[a].append((b, c))
  rev_edge_dict[b].append((a, c))
S, E = map(int, input().split())

visited = [-MAX]*(N+1)
visited[S] = 0
q = deque([(S, 0)])
while q :
  node, dist = q.popleft()
  for nxt, ndist in edge_dict[node] :
    if visited[nxt] < dist + ndist :
      visited[nxt] = dist + ndist
      q.append((nxt, dist + ndist))

print(visited[E])
rev_visited = [False]*(N+1)
rev_visited[E] = True
ans = 0
q = deque([E])
while q :
  node = q.popleft()
  for prev, c in rev_edge_dict[node] :
    if visited[prev] + c != visited[node] :
      continue
    ans += 1
    if not rev_visited[prev] :
      rev_visited[prev] = True
      q.append(prev)
print(ans)

풀이 완료!

'PS > 백준' 카테고리의 다른 글

[백준/1719] 택배 (Python)  (0) 2023.11.17
[백준/1322] X와 K (Python)  (0) 2023.11.16
[백준/1740] 일하는 세포 (Python)  (1) 2023.11.13
[백준/1119] 그래프 (Python)  (1) 2023.11.12
[백준/7578] 공장 (Python)  (1) 2023.11.12
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.