aacord’s memo

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

WUPC 2012 E - 会場への道 (python)

拡張ダイクストラの簡単な問題ということで、まず解いてみました。通常のダイクストラと何が違うかというと、例えば、頂点が3つなら最小距離を保存するリスト d も
d = [float("inf")] * 3 とかで十分でしたが、今回の問題のように、総距離が4の倍数になるものの中で最小のものを考える場合、リストを二次元に拡張して、
d[ i ][ j ] を“頂点 i に行くときの距離で、4で割ったときの余りが j の中で最小のもの”
としないと必要十分に答えを探せなくなる。
分かりやすい図はこちら
WUPC 2012:E - 会場への道 - 数学/競プロメモ
イメージとしては二次元 dp みたいな感じ。
まだ heap に入れるものが余分に1つ増えただけなのと、同じ頂点 d[ i ][ j ] は辿らなくてよいので簡単な方だと思われる。

import heapq
def dijkstra_heap(s,edge,p):
    d = [[float("inf")] * p for i in range(n)] 
# 通常のダイクストラと異なるところその1、あまりの数だけ頂点の数を増やす。(p倍する)
    used = [[True] * p for i in range(n)] # 今回は各頂点の最小値が更新されないので d の数だけ用意するばよい
    d[s][0] = 0
    used[s][0] = False
    ed_list = []
    for es in edge[s]:
        heapq.heappush(ed_list,[es[0],es[1],0]) 
# 異なるところその2、通常の(総距離、次に向かう頂点)に加えて、今の余りの情報が追加されている。
    while len(ed_list):
        poped = heapq.heappop(ed_list)
        md = poped[0]%p
        if not used[poped[1]][md]:
            continue
        v = poped[1]
        d[v][md] = poped[0]
        used[v][md] = False
        for e in edge[v]:
            if used[e[1]][(md+e[0])%p]:
                heapq.heappush(ed_list,[e[0]+poped[0],e[1],md])
        if not used[n-1][0]:
          break
    return d[n-1][0]

import sys
input = sys.stdin.readline
n,m = map(int,input().split())

edge = [[] for i in range(n)]
for i in range(m):
    x,y,z = map(int,input().split())
    if x != n-1:
      edge[x].append([z,y])
    if y != n-1:
      edge[y].append([z,x]) 
print(min(dijkstra_heap(0,edge,4),dijkstra_heap(0,edge,7)))