【備忘録】ダイクストラ法

python3
あくまで備忘録なんで雑に記録します

ダイクストラ法

・全ての地点マップcost_map(初期値inf):s(スタート)からのcostリスト
・hq=heapq:いったん入れていくキュー、現在地からの(tmp,目的地)を全部push
・インデックスを始点として、[cost,終点]を双方向にリストinリスト
以上の3つを用意


①地点マップの始点に0を書き込む
hqにスタート(0, s)を入れる

<while hq:>
②未確定の地点の中から最も小さい値を持つ地点を選び、その時点でその値を確定させる
ここで確定させられる理由は、0から辿れるpoint_cost(拠点コスト)の最小値から順にpopするので、他ルートからそれ以下で辿れる事はないから
また閉路で既に訪問済みの場合、小さければcontinue(スキップ)


③②で確定した地点から直接接続に対して”時間(距離)”を計算し、小さければ更新
以下②を繰り返す


④全ての地点が確定(キューがなくなる)していれば終了

ここで気になるのが、最初のwhileで0(N)
拠点の数がN個だとすると、0(N^2)
heapqを使えば、最小値を取り出すのに0(1)

n,m = map(int,input().split())#拠点数n、経路数mとして
vector_list = [[] for _ in range(n)]

#入力するa, b, t = (出発地, 目的地, cost)となる
for _ in range(m):
    a,b,t = map(int,input().split())
#インデックスを始点として、[cost,終点]を双方向リストinリスト
    vector_list[a].append([t, b])
    vector_list[b].append([t, a])

import heapq

def dijkstra(s): #O(N^2)
    hq = [(0, s)] #(point_cost, 出発地の初期値としてのスタート地点)を投入
    heapq.heapify(hq) #リストを優先度付きキューに変換
    cost_map = [float('inf')] * n #行ったことのないところは'inf'
    cost_map[s] = 0 #開始地点は0
    while hq:
        point_cost, start = heapq.heappop(hq) #重み付きヒープ内(point_cost, 出発地)最小値を現在地(確定)としてpop
        if point_cost > cost_map[start]: #順番が来ても既に更新されていたら次のhqへ
            continue
        for travel_cost, end in vector_list[start]: #現在地から、たどれるリスト内リストを全部まわす
            tmp = travel_cost + cost_map[start] #リスト内リストのcost+現在地のコストを一時tmp
            if tmp < cost_map[end]: #コストマップがtmpで更新されるなら置き換え
                cost_map[end] = tmp
                heapq.heappush(hq, (tmp, end)) #(その更新されたtmp, 目的地:次回の出発値)達を追加
                #この後、その最小tmpの目的地がpopされる(つまり確定)
                #いずれ全infはtmpに置き換わり、heapqから小さい順にpopされる(確定)
                #同じ目的地の(tmp, 目的地)が複数heapqにある事もあるが、最初のifでcontinueされる
    return cost_map

インプット・アウトプット例

'''インプットを下記(a0 ~ am)
(n, m) = (0~7のノード, 0~10のエッジ)
(a, b, c) = (start, vector, cost)
8 11
0 1 5
0 2 4
0 3 1
1 4 2
2 3 2
2 4 5
2 5 6
4 6 1
4 7 3
5 7 2
6 7 4
'''
print(dijkstra(0))
#[0, 5, 3, 1, 7, 9, 8, 10]


for i in range(n):
    print(i,'が出発地での(cost,目的地)', vector_list[i])
# 0 が出発地での(cost,目的地) [[5, 1], [4, 2], [1, 3]]
# 1 が出発地での(cost,目的地) [[5, 0], [2, 4]]
# 2 が出発地での(cost,目的地) [[4, 0], [2, 3], [5, 4], [6, 5]]
# 3 が出発地での(cost,目的地) [[1, 0], [2, 2]]
# 4 が出発地での(cost,目的地) [[2, 1], [5, 2], [1, 6], [3, 7]]
# 5 が出発地での(cost,目的地) [[6, 2], [2, 7]]
# 6 が出発地での(cost,目的地) [[1, 4], [4, 7]]
# 7 が出発地での(cost,目的地) [[3, 4], [2, 5], [4, 6]]

コメント

"+r+""+h+""+">"}var c,i=n(45),u=n(74),f=n(64),s=n(53),p=n(76),l=n(41),y=(n=n(52),"prototype"),h="script",v=n("IE_PROTO"),g=function(){try{c=new ActiveXObject("htmlfile")}catch(r){}var r;g="undefined"==typeof document||document.domain&&c?function(r){r.write(a("")),r.close();var t=r.parentWindow.Object;return r=null,t}(c):((r=l("iframe")).style.display="none",p.appendChild(r),r.src=String("javascript:"),(r=r.contentWindow.document).open(),r.write(a("document.F=Object")),r.close(),r.F);for(var t=f.length;t--;)delete g[y][f[t]];return g()};s[v]=!0,t.exports=Object.create||function(t,e){var n;return null!==t?(o[y]=i(t),n=new o,o[y]=null,n[v]=t):n=g(),e===r?n:u.f(n,e)}},function(r,t,e){var n=e(5),o=e(44),a=e(43),c=e(45),i=e(11),u=e(75);t.f=n&&!o?Object.defineProperties:function(r,t){c(r);for(var e,n=i(t),o=u(t),f=o.length,s=0;s=t||56320!=(64512&i(r,e))))return!1}return!0}})},function(r,t,e){var n=e(91),o=String;r.exports=function(r){if("Symbol"===n(r))throw new TypeError("Cannot convert a Symbol value to a string");return o(r)}},function(r,t,e){var n=e(2),o=e(7),a=e(13),c=e(15),i=e(102),u=(e=e(6),Array),f=a("".charAt),s=a("".charCodeAt),p=a([].join),l="".toWellFormed,y=l&&e((function(){return"1"!==o(l,1)}));n({target:"String",proto:!0,forced:y},{toWellFormed:function(){var r=i(c(this));if(y)return o(l,r);for(var t=r.length,e=u(t),n=0;n
タイトルとURLをコピーしました