최소 신장 트리 - 프림(Prim) 알고리즘
Program Lang./Algorithm 2017. 11. 20. 14:041. 소스 코드
아래 블로그의 설명과 그림을 참조하여 최소 신장 트리 알고리즘 중에 하나인 프림 알고리즘을 구현해 보았다.
우선 순위 큐를 기반으로 구현하였으며, 결과적으로 다른 블로그의 예제와 유사해 보인다.
전체적으로 이해한 바로는 그래프를 너비 우선 순위로 탐색하는 것과 유사하게 구현 뼈대를 가져가고,
단지 Queue에 넣을 때는 일반 Queue가 아닌 우선 순위 큐를 사용하다는 점에 착안하여 구현하는 방향으로
구현해야 한다.
http://swlock.blogspot.kr/2016/02/prim-mstminimum-spanning-tree.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | #include <iostream> #include <vector> #include <queue> #include <functional> struct edgeInfo_t { int from; int to; int weight; }; struct edge_t { int to; int weight; }; const int N = 7; char vtxStr[N] = { 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' }; bool visited[N]; std::vector<edgeInfo_t> result; auto compare = [](edgeInfo_t a, edgeInfo_t b){ return (a.weight > b.weight); }; using priority_queue_t = std::priority_queue<edgeInfo_t, std::vector<edgeInfo_t>, decltype(compare) >; int getIndex( char ch) { for ( int i = 0; i < N; i++) { if (ch == vtxStr[i]) { return i; } } return -1; } void buildGraph(std::vector<edge_t> (&g)[N]) { edgeInfo_t edgeInfo[] = { {getIndex( 'A' ), getIndex( 'B' ), 7}, {getIndex( 'A' ), getIndex( 'D' ), 5}, {getIndex( 'B' ), getIndex( 'C' ), 8}, {getIndex( 'B' ), getIndex( 'E' ), 7}, {getIndex( 'B' ), getIndex( 'D' ), 9}, {getIndex( 'B' ), getIndex( 'A' ), 7}, {getIndex( 'C' ), getIndex( 'E' ), 5}, {getIndex( 'C' ), getIndex( 'B' ), 8}, {getIndex( 'D' ), getIndex( 'A' ), 5}, {getIndex( 'D' ), getIndex( 'B' ), 9}, {getIndex( 'D' ), getIndex( 'E' ), 15}, {getIndex( 'D' ), getIndex( 'F' ), 6}, {getIndex( 'E' ), getIndex( 'C' ), 5}, {getIndex( 'E' ), getIndex( 'G' ), 9}, {getIndex( 'E' ), getIndex( 'F' ), 8}, {getIndex( 'E' ), getIndex( 'D' ), 15}, {getIndex( 'E' ), getIndex( 'B' ), 7}, {getIndex( 'F' ), getIndex( 'E' ), 8}, {getIndex( 'F' ), getIndex( 'G' ), 11}, {getIndex( 'F' ), getIndex( 'D' ), 6}, {getIndex( 'G' ), getIndex( 'E' ), 9}, {getIndex( 'G' ), getIndex( 'F' ), 11}, }; int sz = sizeof (edgeInfo)/ sizeof (edgeInfo[0]); for ( int i = 0; i < sz; i++) { edge_t edge; int v = edgeInfo[i].from; edge.to = edgeInfo[i].to; edge.weight = edgeInfo[i].weight; g[v].push_back(edge); } } void prim( int sIdx, const std::vector<edge_t> (&g)[N], priority_queue_t &q) { for ( int i = 0; i < g[sIdx].size(); i++) { edgeInfo_t edgeInfo; edgeInfo.from = sIdx; edgeInfo.to = g[sIdx][i].to; edgeInfo.weight = g[sIdx][i].weight; q.push(edgeInfo); } visited[sIdx] = true ; while (q.empty() == false ) { edgeInfo_t edgeInfo = q.top(); int target = edgeInfo.to; q.pop(); if (visited[target] == true ) { continue ; } visited[target] = true ; for (auto v : g[target]) { if (visited[v.to] == false ) { edgeInfo_t edgeInfo; edgeInfo.from = target; edgeInfo.to = v.to; edgeInfo.weight = v.weight; q.push(edgeInfo); } } result.push_back(edgeInfo); } } void printGraph( const std::vector<edge_t> (&g)[N]) { for ( int i = 0; i < N; i++) { std:: printf ( "Vertex %c : " , vtxStr[i]); for ( int j = 0; j < g[i].size(); j++) { std:: printf ( "-> %c " , vtxStr[(g[i][j]).to]); } std::cout << std::endl; } } int main() { std::vector<edge_t> graph[N]; priority_queue_t priorityQ(compare); buildGraph(graph); prim(getIndex( 'D' ), graph, priorityQ); //printGraph(graph); for (auto v : result) { std:: printf ( "%c -> %c [%d]\n" , vtxStr[v.from], vtxStr[v.to], v.weight); } return 0; } |
[직관적인 코드]
우선 순위 큐를 사용하지 않고 직관적으로 구현했을 때.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | void prim( int sIdx, const std::vector<edge_t> (&g)[N], std::deque< int > &q) { int min = 0x1FFFFFFF; int idx = 0;; bool visited[N]; for ( int i = 0; i < N; i++) { visited[i] = false ; } q.push_back(sIdx); visited[sIdx] = true ; while (q.size() != N) { min = 0x1FFFFFFF; for (auto i : q) { //std::printf("q = %d ", i); for ( const auto c : g[i]) { //std::printf("c.to = %d ", c.to); if (visited[c.to] == false ) { if (min > c.w) { idx = c.to; min = c.w; //std::printf("idx = %d \n", idx); } } } } q.push_back(idx); visited[idx] = true ; } for (auto i : q) { std:: printf ( "%d, %c \n" , i, strNode[i]); } } |
2. 실행 결과
D -> A [5]
D -> F [6]
A -> B [7]
B -> E [7]
E -> C [5]
E -> G [9]
'Program Lang. > Algorithm' 카테고리의 다른 글
카라츠바 (Karatsuba) - Python (0) | 2023.02.19 |
---|---|
다익스트라(Dijkstra) 알고리즘 - 힙사용하지 않을 경우 (0) | 2017.11.23 |
위상정렬 (Topological Sort) - Indegree (0) | 2017.11.06 |
1로 만들기 (0) | 2017.10.26 |
계단오르기 (0) | 2017.10.25 |