문제 내용
- 도시의 수
N(2<=N<=100,000)
, 면접장의 수K(1<=K<=N)
- 각각의 면접자들이 면접장을 찾아가는 최단 거리의 최댓값을 구하는 문제
- 다익스트라 알고리즘, N명의 면접자들마다 면접장까지의 거리를 예측하도록 함정을 파놓은 것으로 느껴짐 -> 백프로 시간초과 유도
처음 떠오른 아이디어
- 앞서 해결했던 문제 중, 1(출발점) ->
N
(도착점)으로 가는 특정 문제를 해결하는 것을 반대로, N(도착점)에서 나머지들 전체로 가는 문제가 있었다. 해당 문제를 해결하기 위해서, 생각했던 아이디어는A -> B
의 대응관계로 주어진 Edge들을 거꾸로 뒤집어서A <- B
로 대응시킨 뒤에N
에서 나머지들로의 최단거리를 구하면, 결국 한번에 해결해낼 수 있는 것이라는 방법론을 이용해 해결했다. - 또한 앞서 시간초과를 해결하기 위해서, 다익스트라 알고리즘을 heapq를 사용, 방문한 노드는 heaqp에 추가하지 않도록 하여 높은 시간 효율성을 챙길 수 있었다.
- 여기서도 그 생각을 통해 문제를 쉽게 해결할 수 있을 것이라고 짐작했다.
첫 제출
- 위에서 말한 효율적인 다익스트라 사용, 전체 인터뷰장에서 각 도시에 대한 최단거리를 모두 구한 후에 비교하여, 최단 거리를 구하고, 그 중 최대인 거리를 구하는 방식으로 문제를 해결하였다.
total_distance = [] # 인터뷰장 전체에 대한 각 도시까지의 거리 저장 for i in range(K): total_distance.append(dijkstra(interviews[i], edges)) # 다익스트라 수행 max_distance = -1 max_i = 0 for i in range(1, N + 1): tmp = [] for k in range(K): tmp.append(total_distance[k][i]) # 각 인터뷰장까지에 대한 해당 도시의 거리 추가 min_tmp = min(tmp) # 최단거리 구하기 if max_distance < min_tmp: # 그 중 최대를 구하기 위해서 max_distance = min_tmp max_i = i
- 역시 광탈… 1%에서 시간초과를 맞이해버렸다.
두번째 제출
- 공통인 거리 배열을 사용해서, 모든 인터뷰 장에서의 출발은 거리를 0으로 두고 시작한다면, 한번의 반복으로 구해낼 수 있을 것이라고 생각했다.
def dijkstra(start, edges): global dist ... dist = [float('inf')] * (N + 1) for i in range(K): dijkstra(interviews[i], edges)
- 시간 초과… 당연히 최악의 경우에
O(N*Mlog(N))
이 될 수 있기에, 이렇게 해결하면 안됐다. - 근데 이 아이디어 괜찮아보였다. 모든 인터뷰 장에서의 출발은 거리를 0으로 두고 시작 이 방법을 다익스트라 한번으로 풀어볼 수 있을 것 같았다.
세번째 제출
- 다익스트르 수행 처음에 거리배열을
INF
로 초기화 해주고, 탐색 시작 노드의 거리를 0으로 변경해준다. 그럼 이 작업에서, 인터뷰 장 전체의 거리를 0으로 변경해주고 나서 다익스트라를 수행해보면 어떨까?def dijkstra(interview_city, edges): heap = [] dist = [float('inf')] * (N + 1) visited = [False] * (N + 1) for t in interview_city: heapq.heappush(heap, (0, t)) dist[t] = 0 visited[t] = True
- 드디어 시간초과의 늪에서 탈출했다..
전체 코드
from collections import defaultdict
import heapq
def dijkstra(interview_city, edges):
heap = []
dist = [float('inf')] * (N + 1)
visited = [False] * (N + 1)
for t in interview_city:
heapq.heappush(heap, (0, t))
dist[t] = 0
visited[t] = True
while heap:
c, v = heapq.heappop(heap)
if dist[v] < c and visited[v]:
continue
visited[v] = True
for nc, nv in edges[v]:
if dist[nv] > c + nc:
dist[nv] = c + nc
if not visited[nv]:
heapq.heappush(heap, (c + nc, nv))
return dist
N, M, K = map(int, input().split())
edges = defaultdict(list)
for _ in range(M):
U, V, C = map(int, input().split())
edges[V].append((C, U))
interviews = list(map(int, input().split()))
res = dijkstra(interviews, edges)
max_distance = -1
max_i = 0
for i in range(1, N + 1):
if res[i] > max_distance:
max_distance = res[i]
max_i = i
print(max_i)
print(max_distance)
후기
- 어려웠다.. 쉽다고 생각했는데 어려웠다.
- 기본 알고리즘에서 조금의 변주를 주면, 찾는데 시간이 참 오래 걸리는 것 같다.
- 다익스트라 외에도 플로이드-와샬 알고리즘도 한번 전체적으로 정리하는 시간을 가져야 할 것 같다.