์ตœ์†Œ ๋น„์šฉ ์‹ ์žฅ ํŠธ๋ฆฌ (Minimum Cost Spanning Tree)

  • ์‚ฌ์ดํด์ด ์—†๋Š” ์—ฐ๊ฒฐ๋œ ๊ทธ๋ž˜ํ”„๋ผ๋ฉด ์ด๋ฅผ ์‹ ์žฅ ํŠธ๋ฆฌ(spanning tree)๋ผ๊ณ  ํ•œ๋‹ค.
  • ์ตœ์†Œ ๋น„์šฉ ์‹ ์žฅํŠธ๋ฆฌ (Minimum Spanning Tree)๋Š” ๊ฐ€์ค‘์น˜ ๋ฌด๋ฐฉํ–ฅ ๊ทธ๋ž˜ํ”„์—์„œ ๋ชจ๋“  ์ •์ ์„ ์—ฐ๊ฒฐํ•  ๋•Œ ์ตœ์†Œ์˜ ๋น„์šฉ์œผ๋กœ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค.
  • ์ตœ์†Œ๋น„์šฉ์‹ ์žฅ ์•Œ๊ณ ๋ฆฌ์ฆ˜์—๋Š” ํฌ๋ฃจ์Šค์นผ ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ ํ”„๋ฆผ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์กด์žฌํ•œ๋‹ค.

ํƒ์š• ์•Œ๊ณ ๋ฆฌ์ฆ˜(Greedy algorithm)

  • ํฌ๋ฃจ์Šค์นผ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‚˜ ํ”„๋ฆผ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ชจ๋‘ ํƒ์š• ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ํ•œ ์ข…๋ฅ˜
  • ํƒ์š• ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋งค ๋‹จ๊ณ„๋งˆ๋‹ค ํ•ญ์ƒ ์ตœ์ ์ผ ๊ฒƒ ๊ฐ™์€ ์„ ํƒ์„ ํ•˜๋ฉด ์ „์ฒด์ ์œผ๋กœ๋„ ์ตœ์„ ์˜ ์„ ํƒ์„ ํ•˜๊ฒŒ ๋œ๋‹ค๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค.
  • ์ฆ‰, ์—ฌ๋Ÿฌ ๊ฒฝ์šฐ ์ค‘ ํ•˜๋‚˜๋ฅผ ๊ฒฐ์ •ํ•ด์•ผ ํ•  ๋•Œ๋งˆ๋‹ค ๊ทธ ์ˆœ๊ฐ„์— ์ตœ์ ์ด๋ผ๊ณ  ์ƒ๊ฐ๋˜๋Š” ๊ฒƒ์„ ์„ ํƒํ•ด ๋‚˜๊ฐ€๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰ํ•˜์—ฌ ์ตœ์ข…์ ์ธ ํ•ด๋‹ต์— ๋„๋‹ฌํ•œ๋‹ค.
  • ํƒ์š• ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์ ์šฉํ•˜๋ ค๋ฉด ๋‘๊ฐ€์ง€ ์ œ์•ฝ์กฐ๊ฑด์„ ๋งŒ์กฑํ•ด์•ผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๋‘๊ฐ€์ง€ ์ œ์•ฝ ์กฐ๊ฑด์„ ํƒ์š• ํŠน์„ฑ(greedy properties)๋ผ๊ณ  ํ•œ๋‹ค.

์ตœ์  ๋ถ€๋ถ„ ๊ตฌ์กฐ(optional substructure) : ์–ด๋–ค ์ „์ฒด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ตœ์ ํ•ด๋Š” ๋ถ€๋ถ„๋ฌธ์ œ์— ๋Œ€ํ•œ ์ตœ์ ํ•ด๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ๋‹ค.

ํƒ์š• ์„ ํƒ ํŠน์„ฑ(greedy choice property) : ๋ถ€๋ถ„์ ์œผ๋กœ ์ตœ์ ์˜ ์„ ํƒ์„ ๊ณ„์†ํ•˜๋ฉด ์ „์—ญ์ ์œผ๋กœ ์ตœ์ ํ•ด์— ๋„๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ํƒ์š• ์„ ํƒ ํŠน์„ฑ์ธ ์ปท ํ”„๋กœํผํ‹ฐ(cut property)

png

  • V(G) ์ง‘ํ•ฉ์„ ๊ณต์ง‘ํ•ฉ์ด ์•„๋‹Œ ๋‘ ์ง‘ํ•ฉ์œผ๋กœ ๋‚˜๋ˆˆ ๊ฒƒ
  • Crossing edge : ์ปท์œผ๋กœ ๋‚˜๋‰œ ํ•œ ์ง‘ํ•ฉ์˜ ์ •์ ๊ณผ ๋‹ค๋ฅธ ์ง‘ํ•ฉ์˜ ์ •์ ์„ ์—ฐ๊ฒฐ
  • Cut property : Crossing edge ์ค‘ ๊ฐ€์žฅ ์ž‘์€ ์—์ง€๋กœ, MST์˜ ํ•œ ์—์ง€๊ฐ€ ๋œ๋‹ค.
  • Kruskal๊ณผ Prim ๋ชจ๋‘ Cut property ๊ธฐ๋ฐ˜์œผ๋กœ ๋งŒ๋“ค์–ด์กŒ์œผ๋ฉฐ, ๋‹ค๋ฅธ ์ ์€ ์–ด๋–ป๊ฒŒ ์ž๋ฅผ ๊ฒƒ์ธ๊ฐ€์˜ ์ฐจ์ด์ด๋‹ค.

โ‘  ์‹œ์ž‘์ ์—์„œ ์ธ์ ‘ํ•œ ์ •์ ์„ ์ฃผ๋ณ€์œผ๋กœ ์ปท์„ ์ฐพ๋Š”๋‹ค. crossing edge ์ค‘์—์„œ ๊ฐ€์ค‘์น˜๊ฐ€ ๊ฐ€์žฅ ์ž‘์€ ์—์ง€์ธ 2๋ฅผ ์„ ํƒํ•œ๋‹ค.

png

โ‘ก crossing edge ์ค‘์—์„œ ๊ฐ€์ค‘์น˜๊ฐ€ ๊ฐ€์žฅ ์ž‘์€ ์—์ง€์ธ 7์„ ์„ ํƒํ•œ๋‹ค. ์„ ํƒ๋œ crossing edge๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š๋Š” ์ปท์„ ์ฐพ๋Š”๋‹ค.

png

โ‘ข crossing edge ์ค‘์—์„œ ๊ฐ€์ค‘์น˜๊ฐ€ ๊ฐ€์žฅ ์ž‘์€ ์—์ง€์ธ 5๋ฅผ ์„ ํƒํ•œ๋‹ค.

png

โ‘ฃ crossing edge ์ค‘์—์„œ ๊ฐ€์ค‘์น˜๊ฐ€ ๊ฐ€์žฅ ์ž‘์€ ์—์ง€์ธ 4๋ฅผ ์„ ํƒํ•œ๋‹ค. โ‘ค png

png

ํฌ๋ฃจ์Šค์นผ ์•Œ๊ณ ๋ฆฌ์ฆ˜(Kruskal algorithm)

  • ๊ฐ€์žฅ ์ ์€ ๋น„์šฉ์œผ๋กœ ๋ชจ๋“  ๋…ธ๋“œ๋ฅผ ์—ฐ๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜
  • ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋„์‹œ๊ฐ€ ์žˆ์„ ๋•Œ, ๊ฐ ๋„์‹œ ์‚ฌ์ด๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ๋„๋กœ๋ฅผ ์ตœ์†Œํ•œ์˜ ๋น„์šฉ์œผ๋กœ ๊ฑด์„คํ•˜๊ณ  ํ•  ๋•Œ ์ ์šฉ๋˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜

ํฌ๋ฃจ์Šค์นผ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋™์ž‘

  1. ๊ทธ๋ž˜ํ”„์˜ ๊ฐ„์„ ๋“ค์„ ๊ฐ€์ค‘์น˜์˜ ์˜ค๋ฆ„์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌํ•œ๋‹ค.
  2. ์ •๋ ฌ๋œ ๊ฐ„์„  ๋ฆฌ์ŠคํŠธ์—์„œ ์ˆœ์„œ๋Œ€๋กœ ์‚ฌ์ดํด์„ ํ˜•์„ฑํ•˜์ง€ ์•Š๋Š” ๊ฐ„์„ ์„ ์„ ํƒํ•œ๋‹ค. ์ฆ‰, ๊ฐ€์žฅ ๋‚ฎ์€ ๊ฐ€์ค‘์น˜๋ฅผ ๋จผ์ € ์„ ํƒํ•œ๋‹ค.
  3. ์‚ฌ์ดํด์„ ํ˜•์„ฑํ•˜๋Š” ๊ฐ„์„ ์„ ์ œ์™ธํ•œ๋‹ค.
  4. ํ•ด๋‹น ๊ฐ„์„ ์„ ํ˜„์žฌ์˜ MST(์ตœ์†Œ ๋น„์šฉ ์‹ ์žฅ ํŠธ๋ฆฌ)์˜ ์ง‘ํ•ฉ์— ์ถ”๊ฐ€ํ•œ๋‹ค.

์‚ฌ์ดํด์ด ํ˜•์„ฑ๋˜๋Š”์ง€ ์–ด๋–ป๊ฒŒ ํ™•์ธํ•˜์ง€?

  • ์„œ๋กœ ๋‹ค๋ฅธ ๋‘ ์ง‘ํ•ฉ์„ ๋ณ‘ํ•ฉํ•˜๋Š” Union ์—ฐ์‚ฐ, ์ง‘ํ•ฉ ์›์†Œ๊ฐ€ ์–ด๋–ค ์ง‘ํ•ฉ์— ์†ํ•ด์žˆ๋Š”์ง€ ์ฐพ๋Š” Find ์—ฐ์‚ฐ์„ ํ™œ์šฉํ•œ๋‹ค.

png

  • parent ๋ฐฐ์—ด์€ ๊ฐ ์ •์ ์˜ root node(๋ถ€๋ชจ)๋ฅผ ํ‘œํ˜„ํ•œ ๋ฐฐ์—ด
  • ๊ฐ„์„  ์„ ํƒ ์ „, ์ดˆ๊ธฐ์—๋Š” ์ž๊ธฐ ์ž์‹ ์ด ๋ฃจํŠธ ๋…ธ๋“œ๊ฐ€ ๋˜๊ฒŒ ์ดˆ๊ธฐํ™” ๋˜์–ด ์žˆ๋Š” ์ƒํƒœ (parent[i] = i)

png

  • find ์—ฐ์‚ฐ์„ ์ด์šฉํ•˜์—ฌ ์—์ง€(0,1)์˜ ์ •์  0๊ณผ ์ •์  1๊ฐ€ ์‚ฌ์ดํด์ด ํ˜•์„ฑํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.
  • ์‚ฌ์ดํด์ด ํ˜•์„ฑ๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด union์—ฐ์‚ฐ์„ ์ด์šฉํ•˜์—ฌ ๋‘์ง‘ํ•ฉ์„ ํ•˜๋‚˜๋กœ ํ•ฉ์ณ์ค€๋‹ค.

png

ํฌ๋ฃจ์Šค์นผ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋™์ž‘๊ณผ์ •

png

png

png

png

png

png

png

png

png

png

png

png

png

from disjoint_set import DisjointSet

class Edge:
    # ์‹œ์ž‘์ •์ , ๋์ •์ , ๊ฐ€์ค‘์น˜ ์ดˆ๊ธฐํ™”
    def __init__(self, u, v, w):
        self.u=u
        self.v=v
        self.w=w

class Graph:
    def __init__(self, vertex_num):
        self.adj_list=[[] for _ in range(vertex_num)]
        self.edge_list=[]

        self.vertex_num=vertex_num

    def add_edge(self, u, v, weight):
        self.adj_list[u].append(v)
        self.adj_list[v].append(u)

        self.edge_list.append(Edge(u, v, weight))

    def MST_kruskal(self):
        mst=Graph(self.vertex_num)     ## ์ตœ์ข…์ ์œผ๋กœ ๋งŒ๋“ค ์ตœ์†Œ๋น„์šฉ ์‹ ์žฅ ํŠธ๋ฆฌ    
        ds=DisjointSet(self.vertex_num)  ## ์‚ฌ์ดํด ํ˜•์„ฑ ๊ฒ€์‚ฌ๋ฅผ ํ•  ์ •์ ‘ ์ง‘ํ•ฉ
        self.edge_list.sort(key=lambda e: e.w)  ## ๊ฐ€์ค‘์น˜์— ๋”ฐ๋ผ ์—์ง€ ์ •๋ ฌ
        mst_edge_num=0
        edge_idx=0  ## ์ •๋ ฌ๋œ ์—์ง€ ๋ฆฌ์ŠคํŠธ์—์„œ ์ธ๋ฑ์Šค

        while mst_edge_num < self.vertex_num-1:
            edge=self.edge_list[edge_idx]
            if ds.collapsing_find(edge.u) != ds.collapsing_find(edge.v):
                ## find ์—ฐ์‚ฐ์„ ํ™œ์šฉํ•˜์—ฌ ์ง‘ํ•ฉ ์›์†Œ๊ฐ€ ์–ด๋–ค ์ง‘ํ•ฉ์— ์†ํ•ด์žˆ๋Š”์ง€ ํ™•์ธ
                mst.add_edge(edge.u, edge.v, edge.w)
                ds.weighted_union(ds.collapsing_find(edge.u), ds.collapsing_find(edge.v))
                # union ์—ฐ์‚ฐ์„ ํ™œ์šฉํ•˜์—ฌ ๋‘์ง‘ํ•ฉ ๋ณ‘ํ•ฉ
                mst_edge_num+=1
            edge_idx+=1

        return mst

    def print_edges(self):
        for edge in self.edge_list:
            print("({}, {}) : {}".format(edge.u, edge.v, edge.w))

if __name__=="__main__":
    g=Graph(6)

    g.add_edge(0, 1, 10)
    g.add_edge(0, 2, 2)
    g.add_edge(0, 3, 8)
    g.add_edge(1, 2, 5)
    g.add_edge(1, 4, 12)
    g.add_edge(2, 3, 7)
    g.add_edge(2, 4, 17)
    g.add_edge(3, 4, 4)
    g.add_edge(3, 5, 14)

    mst=g.MST_kruskal()

    mst.print_edges()

class DisjointSet:
    def __init__(self, vnum):
        self.parent=[-1 for _ in range(vnum)]

    def simple_find(self, i):
        while self.parent[i] >= 0:
            i=self.parent[i]
        return i

    def simple_union(self, i, j):
        self.parent[i]=j

    def collapsing_find(self, i):
        root=trail=lead=None
        # ๋ฃจํŠธ๋ฅผ ์ฐพ๋Š”๋‹ค.
        root=i
        while self.parent[root] >= 0:
            root=self.parent[root]

        # ๋ชจ๋“  ๋…ธ๋“œ๋ฅผ ๋ฃจํŠธ์˜ ์ž์‹์œผ๋กœ ๋งŒ๋“ ๋‹ค
        trail=i
        while trail != root:
            lead=self.parent[trail]
            self.parent[trail]=root
            trail=lead

        return root

    def weighted_union(self, i, j):
        """
        paremeters i, j must be roots!
        if size[i] < size[j] then parent[i]=j
        """
        #abs(parent[i])=size[i]
        #temp_cnt๋Š” ์Œ์ˆ˜์ด๊ณ  size[i] + size[j]
        temp_cnt=self.parent[i]+self.parent[j]

        # ๊ฐ ์ง‘ํ•ฉ์ด ๊ฐ€์ง„ ๋…ธ๋“œ ๊ฐœ์ˆ˜๋ฅผ ๋น„๊ตํ•˜์—ฌ ๋…ธ๋“œ๊ฐœ์ˆ˜๊ฐ€ ๋งŽ์€ ์ง‘ํ•ฉ์— ๋…ธ๋“œ ๊ฐœ์ˆ˜๊ฐ€ ์ ์€ ์ง‘ํ•ฉ์„ ์ž์‹์œผ๋กœ ๋ณ‘ํ•ฉ
        #size[i] < size[j]
        if self.parent[i] > self.parent[j]:
            self.parent[i]=j
            self.parent[j]=temp_cnt
        #size[i] > size[j]
        else:
            self.parent[j]=i
            self.parent[i]=temp_cnt

if __name__=="__main__":
    ds=DisjointSet(5)

    # ds.simple_union(1, 2)
    # ds.simple_union(4, 2)
    # ds.simple_union(3, 0)
    # print(ds.parent)
    
    # for i in range(5):
    #     print("parent[{}] : {}".format(i, ds.simple_find(i)))

    ds=DisjointSet(5)
    ds.parent[2]=-5
    ds.parent[4]=2
    ds.parent[0]=4
    ds.parent[1]=0
    ds.parent[3]=1
    print(ds.parent)
    print("the root is {}".format(ds.collapsing_find(3)))
    print(ds.parent)
    

ํ”„๋ฆผ ์•Œ๊ณ ๋ฆฌ์ฆ˜

  • ์‹œ์ž‘ ์ •์ ์„ ์„ ํƒํ•œ ํ›„, ์ •์ ์— ์ธ์ ‘ํ•œ ๊ฐ„์„  ์ค‘ ์ตœ์†Œ ๊ฐ„์„ ์œผ๋กœ ์—ฐ๊ฒฐ๋œ ์ •์ ์„ ์„ ํƒํ•˜๊ณ , ํ•ด๋‹น ์ •์ ์—์„œ ๋‹ค์‹œ ์ตœ์†Œ ๊ฐ„์„ ์œผ๋กœ ์—ฐ๊ฒฐ๋œ ์ •์ ์„ ์„ ํƒํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ตœ์†Œ ์‹ ์žฅ ํŠธ๋ฆฌ๋ฅผ ํ™•์žฅํ•ด๊ฐ€๋Š” ๋ฐฉ์‹
  • Kruskalโ€™s algorithm ๊ณผ Primโ€™s algorithm ๋น„๊ต

  • ๋‘˜๋‹ค, ํƒ์š• ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ธฐ์ดˆ๋กœ ํ•˜๊ณ  ์žˆ์Œ (๋‹น์žฅ ๋ˆˆ ์•ž์˜ ์ตœ์†Œ ๋น„์šฉ์„ ์„ ํƒํ•ด์„œ, ๊ฒฐ๊ณผ์ ์œผ๋กœ ์ตœ์ ์˜ ์†”๋ฃจ์…˜์„ ์ฐพ์Œ)

  • Kruskalโ€™s algorithm์€ ๊ฐ€์žฅ ๊ฐ€์ค‘์น˜๊ฐ€ ์ž‘์€ ๊ฐ„์„ ๋ถ€ํ„ฐ ์„ ํƒํ•˜๋ฉด์„œ MST๋ฅผ ๊ตฌํ•จ

  • Primโ€™s algorithm์€ ํŠน์ • ์ •์ ์—์„œ ์‹œ์ž‘, ํ•ด๋‹น ์ •์ ์— ์—ฐ๊ฒฐ๋œ ๊ฐ€์žฅ ๊ฐ€์ค‘์น˜๊ฐ€ ์ž‘์€ ๊ฐ„์„ ์„ ์„ ํƒ, ๊ฐ„์„ ์œผ๋กœ ์—ฐ๊ฒฐ๋œ ์ •์ ๋“ค์— ์—ฐ๊ฒฐ๋œ ๊ฐ„์„  ์ค‘์—์„œ ๊ฐ€์žฅ ๊ฐ€์ค‘์น˜๊ฐ€ ์ž‘์€ ๊ฐ„์„ ์„ ํƒํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ MST๋ฅผ ๊ตฌํ•จ

ํ”„๋ฆผ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋™์ž‘๊ณผ์ •

png

import math
from min_heap import Element, MinHeap

class Edge:
    def __init__(self, u, v, w):
        self.u=u
        self.v=v
        self.w=w

class Graph:
    def __init__(self, vertex_num):
        self.adj_list=[[] for _ in range(vertex_num)]
        self.edge_list=[]

        self.vertex_num=vertex_num

    def add_edge(self, u, v, w):
        # (์ •์ , ์—์ง€์˜ ๊ฐ€์ค‘์น˜)๋ฅผ ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€
        self.adj_list[u].append((v, w))
        self.adj_list[v].append((u, w))

        self.edge_list.append(Edge(u, v, w))

    def MST_prim(self):
        mst=Graph(self.vertex_num)

        w_list=[math.inf for _ in range(self.vertex_num)]
        # w_list = [inf,inf,inf,inf,inf,inf]
        TV=set()
        h=MinHeap()

        # Element ๊ฐ์ฒด: ๊ฐ€์ค‘์น˜๋ฅผ ํ‚ค๋กœ ์‚ฌ์šฉํ•œ๋‹ค.
        for i in range(1, self.vertex_num):
            h.push(Element(i, math.inf, None))

        w_list[0]=0
        h.push(Element(0, 0, None))
        
        while not h.is_empty():
            elem_v=h.pop()
            v=elem_v.v 
            w=elem_v.w 
            _from=elem_v._from
            
            TV.add(v)
            if _from != None:
                mst.add_edge(v, _from, w)
            
            adj_v=self.adj_list[v]
            # ๋…ธ๋“œ 0์ผ ๊ฒฝ์šฐ 
            # adj_v = [(1,10),(2,2),(3,8)]
            for u, w_u_v in adj_v:
                if u not in TV and w_u_v < w_list[u]:
                    # TV ์ด์ „์— ๋…ธ๋“œ๋ฅผ ๋ฐฉ๋ฌธํ–ˆ๋Š”์ง€ ์ฒดํฌ ํ•˜๊ธฐ ์œ„ํ•œ ์šฉ๋„
                    w_list[u]=w_u_v
                    h.decrease_weight(Element(u, w_u_v, v))
                    # u : ๋์ •์ , w_u_v : ๊ฐ€์ค‘์น˜, v : ์‹œ์ž‘์ •์ 

        '''
        # ์ƒˆ๋กœ์šด ๊ฐ€์ค‘์น˜๊ฐ€ ๊ธฐ์กด ๊ฐ€์ค‘์น˜๋ณด๋‹ค ์ž‘๋‹ค๋ฉด decrease_weight ์—ฐ์‚ฐ
        def decrease_weight(self, new_elem):
            cur=self.pos[new_elem.v]

            while cur!= 1 and new_elem.w < self.arr[self.parent(cur)].w:
                self.arr[cur]=self.arr[self.parent(cur)]
                self.pos[self.arr[cur].v]=cur    

                cur=self.parent(cur)

            self.arr[cur]=new_elem
            self.pos[new_elem.v]=cur
        '''
        
        '''
        ๊ฒฐ๊ณผ๊ฐ’
        (2, 0) : 2
        (1, 2) : 5
        (3, 2) : 7
        (4, 3) : 4
        (5, 3) : 14
        '''
        return mst

    def print_edges(self):
        for edge in self.edge_list:
            print("({}, {}) : {}".format(edge.u, edge.v, edge.w))

if __name__=="__main__":
    g=Graph(6)

    g.add_edge(0, 1, 10)
    g.add_edge(0, 2, 2)
    g.add_edge(0, 3, 8)
    g.add_edge(1, 2, 5)
    g.add_edge(1, 4, 12)
    g.add_edge(2, 3, 7)
    g.add_edge(2, 4, 17)
    g.add_edge(3, 4, 4)
    g.add_edge(3, 5, 14)

    mst=g.MST_prim()

    mst.print_edges()