사용자 도구

사이트 도구


ps:problems:boj:2982

국왕의 방문

ps
링크acmicpc.net/…
출처BOJ
문제 번호2982
문제명국왕의 방문
레벨골드 2
분류

다익스트라

시간복잡도O(ElogV)
인풋사이즈V<=1000, E<=10000
사용한 언어Python
제출기록32928KB / 92ms
최고기록84ms
해결날짜2022/03/16

풀이

  • 발상:★★, 구현:★★
  • 우선 문제 이해에 좀 시간이 걸렸다. 기본적으로는 최단 경로 문제이긴 한데, 특정 시간에는 특정 엣지를 이용할수 없다는 제약이 들어간다.
  • 제약을 바꿔서 생각하면, 엣지를 사용할수 없는 시간에는 엣지가 사용가능해질때까지 기다렸다가 이동을 하게 되므로, 그냥 엣지의 웨이트가 더 증가한다고 생각할수 있다. 그러면, 엣지의 코스트가 엣지의 시작 노드까지 도달하는데에 사용된 코스트에 따라 바뀌는 문제라고 생각할 수 있다.
  • 다행히도, u→v 엣지를 지나갈 때 엣지의 코스트가 바뀌더라도, u에 가장 빨리 도달했을때가 v에도 가장 빨리 도달하게 된다. 따라서 다익스트라 알고리즘을 사용해서 최단 경로를 구할 수 있다. (다익스트라 참고)
  • 이제 저렇게 엣지의 코스트가 바뀌는 것을 고려해서 다익스트라를 구현하면 된다. 시간복잡도는 O(ElogV). teflib.tgraph.dijkstra를 그대로 사용할수는 없어서, 로직을 수정해서 새로 짰다.
  • 국왕이 지나가는 엣지들에 대해서 사용불가능한 시간 범위을 계산해서 저장해주어야 한다. 이때, 시간 범위의 시작을 -K로 하면, 비교할때 좀더 간단하다.

코드

"""Solution code for "BOJ 2982. 국왕의 방문".

- Problem link: https://www.acmicpc.net/problem/2982
- Solution link: http://www.teferi.net/ps/problems/boj/2982

Tags: [Dijkstra]
"""

import heapq
import itertools
import sys

INF = float('inf')


def dijkstra(wgraph, blocked_period, source, dest):
    distances = [INF] * len(wgraph)
    distances[source] = 0
    heap = [(0, source)]
    while heap:
        dist_u, u = heapq.heappop(heap)
        if dist_u != distances[u]:
            continue
        if u == dest:
            return dist_u
        for v, dist_uv in wgraph[u].items():
            if ((period := blocked_period.get((u, v))) and
                    period[0] <= dist_u < period[1]):
                dist_v = period[1] + dist_uv
            else:
                dist_v = dist_u + dist_uv
            if dist_v < distances[v]:
                distances[v] = dist_v
                heapq.heappush(heap, (dist_v, v))


def main():
    N, M = [int(x) for x in sys.stdin.readline().split()]
    wgraph = [{} for _ in range(N)]
    # pylint: disable=unused-variable
    A, B, K, G = [int(x) for x in sys.stdin.readline().split()]
    route = [int(x) for x in sys.stdin.readline().split()]
    for _ in range(M):
        U, V, L = [int(x) for x in sys.stdin.readline().split()]
        wgraph[U - 1][V - 1] = wgraph[V - 1][U - 1] = L

    blocked_period = {}
    beg = -K
    for u, v in itertools.pairwise(route):
        end = beg + wgraph[u - 1][v - 1]
        blocked_period[u - 1, v - 1] = blocked_period[v - 1, u - 1] = (beg, end)
        beg = end

    print(dijkstra(wgraph, blocked_period, A - 1, B - 1))


if __name__ == '__main__':
    main()

토론

댓글을 입력하세요:
W G V X᠎ O
 
ps/problems/boj/2982.txt · 마지막으로 수정됨: 2022/03/16 05:45 저자 teferi