kb84tkhrのブログ

何を書こうか考え中です あ、あと組織とは関係ないってやつです 個人的なやつ

ALDS1_12_B: Single Source Shortest Path I (続き)

解説
今度は隣接行列にしてるのか
気が合いませんね(そういう問題?

ダイクストラ
たしかレナの本にも出てたな(名前しか記憶がない

グラフG=(V, E)、始点をs、最短経路木に含まれる頂点の集合をS、
sから各頂点iまでのコストをd[i]、iの親をp[i]とする

S={}、d[s]=0、s以外の頂点iについてd[i]=∞に初期化する
S=Vになるまで以下を繰り返す
V-Sからd[u]が最小であるuを選択する
uをSに追加する
uに隣接しV-Sの属する頂点vについてd[v]とp[v]を更新する

という作戦とサンプルコードを参考にしつつ修正

def shortest_path(n, adj_list):
    color = [WHITE] * n
    dist = [maxsize] * n

    dist[0] = 0
    color[0] = GRAY

    while True:
        minv = maxsize
        u = -1
        for i in range(n):
            if minv > dist[i] and color[i] != BLACK:
                u = i
                minv = dist[i]

        if u == -1:
            break
        color[u] = BLACK

        for v, c in adj_list[u]:
            if dist[u] + c < dist[v]:
                dist[v] = dist[u] + c
                color[v] = GRAY

    return dist

テスト#6が00.02s
20倍速くなった(なお有効数字

全体的な流れはMinimun Spanning Treeと似てるんだな
境界上で最短となる辺を探すから無駄が少ないと
IIでは速い方法を考えるのか?

思い立ってインデックスでループを回すのをやめてみた

class Node:
    WHITE = 0
    GRAY = 1
    BLACK = 2

    def __init__(self):
        self.adjs = []
        self.color = Node.WHITE
        self.dist = maxsize

def read_adj():
    n = int(input())
    nodes = [Node() for _ in range(n)]

    for i in range(n):
        u, _, *rest = [int(x) for x in input().split()]
        for i in range(0, len(rest) - 1, 2):
            nodes[u].adjs.append((nodes[rest[i]], rest[i+1]))

    return nodes

def shortest_path(nodes):
    nodes[0].dist = 0
    nodes[0].color = Node.GRAY

    while True:
        min_node = min(
            [n for n in nodes if n.color != Node.BLACK],
            default=None, key=lambda n: n.dist)

        if min_node is None:
            break
        min_node.color = Node.BLACK

        for adj, c in min_node.adjs:
            if min_node.dist + c < adj.dist:
                adj.dist = min_node.dist + c
                adj.color = Node.GRAY