출처 - https://www.acmicpc.net/problem/2982

로직은 쉽게 생각할 수 있는 다익스트라 문제였다. 다만 국왕이 도로를 점유하고 있는 상황을 표현하는 방법이 조금 까다로웠다. 메모리를 비효율적으로 사용하더라도 우선 풀어야겠다고 생각했다. 인접 행렬과 인접 리스트를 모두 사용하여 국왕의 위치를 표시했다.

1. 풀이

  • path[u][v]에 u에서 v로 국왕이 이동을 시작한 시간, 도착한 시간을 저장한다. 양방향 그래프이므로 방향과 관계 없이 path[u][v], path[v][u]를 똑같은 값으로 저장한다.
  • 다익스트라에서 출발 지점의 초기 거리값을 K로 갱신하여 국왕이 이동하는 시간과 동기화할 수 있다. 이후 도착 시간에서 K를 빼면 이동 시간을 구할 수 있다.
  • 다익스트라를 수행하며 현재 노드(node), 다음 노드(next) 사이를 국왕이 지나간 시간을 확인한다. path[node][next] = 출발시간, 도착시간
  • 만약 내가 node에 도착한 시간이 출발시간과 도착시간 사이에 있다면 나의 출발 시간을 국왕의 도착시간으로 갱신한다.
  • 다익스트라가 종료되면 B에 도착한 최소 시간에서 출발 시간인 K를 빼고 출력한다.

2. 코드

# boj-2982.py
from heapq import heappop, heappush

N,M = map(int, input().split())
A,B,K,G = map(int, input().split())
king = list(map(int, input().split()))
graph =  [ [] for _ in range(N+1) ]
graph2= [ [0 for _ in range(N+1)] for _ in range(N+1) ]
for _ in range(M):
    u,v,w = map(int, input().split())
    graph[u].append([v,w])
    graph[v].append([u,w])
    graph2[u][v] = w
    graph2[v][u] = w
    
path = [ [ [-1,-1] for _ in range(N+1)] for _ in range(N+1) ]
time = 0
for i in range(1, G):
    before = king[i-1]
    node = king[i]
    path[before][node] = time, time + graph2[before][node]
    path[node][before] = time, time + graph2[before][node]
    time += graph2[before][node]

dist = [float('inf') for _ in range(N+1)]
dist[A]=K
heap = [[K,A]]

while heap:
    cost, node = heappop(heap)
    
    if dist[node] < cost :
        continue
        
    for next, weight in graph[node]:
        
        my_start= cost
        king_start, king_end = path[node][next]
        if king_start<=my_start<=king_end :
            my_start = king_end
        
        if dist[next] > my_start+weight :
            dist[next] = my_start+weight
            heappush(heap, [dist[next], next])

print(dist[B]-K)

2.2 코드(오답)

아래와 같이 인접 리스트만 이용하여 풀었지만 51퍼센트에서 틀렸다. 왜 그런지 아직도 모르겠다.

# boj-2982.py
from heapq import heappop, heappush

N,M = map(int, input().split())
A,B,K,G = map(int, input().split())
king = list(map(int, input().split()))
graph =  [ [] for _ in range(N+1) ]
for _ in range(M):
    u,v,w = map(int, input().split())
    graph[u].append([v,w])
    graph[v].append([u,w])
    
path = [[-1,-1]for _ in range(N+1)]
if G>=1:
    path[king[0]] = [0,0]
    time = 0
    for i in range(1, len(king)):
        node = king[i]
        before = king[i-1]
    
        for next, cost in graph[before]:
            if next== node:
                time += cost
                #어디서 왔는지?, 여기서 다시 출발 시간 언제야? (여기 도착시간)
                path[node] = [before, time]
                break

dist = [float('inf') for _ in range(N+1)]
dist[A]=K
heap = [[K,A]]

while heap:
    cost, node = heappop(heap)
    if dist[node] < cost :
        continue
        
    for next, weight in graph[node]:
        
        my_start,my_end = cost, cost+weight
        #내 출발 지점과 왕 출발지점 같을 때
        if path[next][0] ==node :
            king_start, king_end = path[node][1], path[next][1]
            if king_start<=my_start<king_end :
                my_start = king_end

        #내 출발지점과 왕의 도착 지점이 같을 때
        elif path[node][0] ==next:
            king_start, king_end = path[next][1], path[node][1]
            if king_start<=my_start<king_end:
                my_start = king_end

            
        if dist[next] > my_start+weight :
            dist[next] = my_start+weight
            heappush(heap, [dist[next], next])

print(dist[B]-K)

업데이트:

댓글남기기