最小全域問題をプリム法で解く
最小全域木問題を学習中。プリム法を使って最小全域木を求める。応用が広いみたい。
以下の平面座標上の点の最小全域木を求める。
a = (18, 25)
b = (36, 50)
c = (36, 27)
d = (46, 37)
e = (73, 37)
f = (65, 12)
それぞれのノードが、自分を除く全てのノードへエッジをもつとする。
http://www.deqnotes.net/acmicpc/prim/
手計算で求めたらコストが101.9で辺が
a,c
c,d
d,b
d,e
e,f
だった。
# coding: utf8 # # 平面座標上の完全グラフの最小全域木問題 # # from math import sqrt INF = 10**12 class Point: def __init__(s, x, y): s.x = x s.y = y def euclid_dist(u, v): # 2点間の距離 return sqrt((u.x - v.x)**2 + (u.y - v.y)**2) def MST(ps): # Minimum Spanning Tree # 距離行列の作成 m = [[euclid_dist(ps[i], ps[j]) for i in xrange(len(ps))] for j in xrange(len(ps))] # 集合の初期化 X = set([0]) Y = set(range(len(ps))[1:]) # cost = 0 edges = [] print X, Y while len(Y) != 0: mcost = INF edge = None for ex in X: for ey in Y: if mcost > m[ex][ey]: mcost = m[ex][ey] edge = [ex, ey] print "[MST]: minimum path is", edge X.add(edge[1]) Y.remove(edge[1]) cost += mcost edges.append(edge) return cost, edges def main(): points = [[18, 25], [36, 50], [36, 27], [46, 37], [73, 37], [65, 12],] ps = [Point(*p) for p in points] cost, edges = MST(ps) vname = dict( zip(range(len(ps)), [c for c in "abcdef"]) ) print "Cost:", cost print "Path:" for edge in edges: print "%s -> %s" % (vname[edge[0]], vname[edge[1]]) if __name__ == '__main__': main()
実行
set([0]) set([1, 2, 3, 4, 5]) [MST]: minimum cost path is [0, 2] [MST]: minimum cost path is [2, 3] [MST]: minimum cost path is [3, 1] [MST]: minimum cost path is [3, 4] [MST]: minimum cost path is [4, 5] Cost: 101.902934864 Path: a -> c c -> d d -> b d -> e e -> f