aacord’s memo

abcを中心にpythonで解いた問題のメモ、整理をしています。緑になった。

abc 164 E - Two Currencies (python)

拡張ダイクストラで解く。総時間、頂点に加えて今持っている銀貨の数を追加して heap に入れる。時間を増やす要因が通過時間と通貨を交換する時間の二つ(疲れているのでダジャレみたいになっている)あるので、交換するか、移動するかで分けて考える。移動に必要な銀貨が足りないものは heap に入れなければok
ほんとは 1 から i までの最短時間を n回ダイクストラで求めたいのだが、それだと TLE したので、heap なので初めて頂点 i に到着した時間 == 1 から i までの最短時間とすることができるので、頂点に初めて到着するごとに、その頂点とかかった時間をリストに入れて、頂点順に並び替えて出力した。これで青diff ですか…

import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines

from heapq import heappush, heappop

N,M,S = map(int,readline().split())
ABC = [list(map(int,readline().split())) for _ in range(M)]
m = map(int,read().split())
CD = list(zip(m,m))

graph = [[] for _ in range(N)]
for u,v,a,b in ABC:
    graph[u-1].append((v-1,a,b))
    graph[v-1].append((u-1,a,b))

def f():
  INF = 10 ** 18
  arrive = [False]*N # その頂点に到着したことがあるか
  ans = []
  qq = 2451
  dist = [[INF] * qq for _ in range(N)]
  dist[0][min(qq-1,S)] = 0
  q = [(0,min(qq-1,S),0)]
  while q:
      st,ss,v = heappop(q) # 総時間、銀貨、今いる頂点
      if dist[v][ss] < st:
        continue
      if not arrive[v]:
        arrive[v] = True
        ans.append((v,st)) # 初めて頂点 v に来たなら、その頂点と時間をリストにいれる
        if all(arrive):
          break
      c,d = CD[v]
      # 銀貨の購入
      if ss < qq-1:
          ns = min(ss + c, qq-1)
          nt = st + d
          if dist[v][ns] > nt:
              dist[v][ns] = nt
              heappush(q,(nt,ns,v)) # 銀貨を購入するだけで移動はしない
      # 移動
      for nex,g,tt in graph[v]: # 次の頂点、必要な銀貨、通過にかかる時間
          if ss-g < 0:
              continue
          dt = st + tt
          if dist[nex][ss-g] <= dt:
# heapに入れる前に最小値を更新しないと分かっているものは枝刈りしておくと若干早くなる
              continue
          dist[nex][ss-g] = dt
          heappush(q,(dt,ss-g,nex))
  return ans

ab = f()
from operator import itemgetter
ab = sorted(ab,key=itemgetter(0)) # 頂点順に並び替え
for i in range(1,N):
  print(ab[i][1])