Prim算法
Prim算法是一种用于寻找加权连通图的最小生成树(MST)的贪心算法。该算法从任意一个顶点开始,逐步将最近的未访问过的顶点添加到正在构建的最小生成树中,直到所有顶点都被包含在内。
代码实现
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
| #include <iostream> #include <vector> #include <queue> #include <climits>
using namespace std;
const int MAX = 100; int graph[MAX][MAX]; bool visited[MAX]; int parent[MAX]; int key[MAX]; int V;
void updateKeys(int u) { for (int v = 0; v < V; ++v) { if (graph[u][v] && !visited[v]) { if (graph[u][v] < key[v]) { parent[v] = u; key[v] = graph[u][v]; } } } }
int findMinKeyVertex() { int minKey = INT_MAX, minVertex = -1; for (int v = 0; v < V; ++v) { if (!visited[v] && key[v] < minKey) { minKey = key[v]; minVertex = v; } } return minVertex; }
void primMST() { for (int i = 0; i < V; ++i) { key[i] = INT_MAX; parent[i] = -1; visited[i] = false; }
int startVertex = 0; key[startVertex] = 0;
for (int count = 0; count < V - 1; ++count) { int u = findMinKeyVertex(); visited[u] = true;
updateKeys(u); }
cout << "Edge \tWeight\n"; for (int i = 1; i < V; ++i) { cout << parent[i] << " - " << i << "\t" << graph[i][parent[i]] << endl; } }
int main() { V = 5; memset(graph, 0, sizeof(graph));
graph[0][1] = 2; graph[1][0] = 2; graph[0][3] = 6; graph[3][0] = 6; graph[1][2] = 3; graph[2][1] = 3; graph[1][3] = 8; graph[3][1] = 8; graph[1][4] = 5; graph[4][1] = 5; graph[2][4] = 7; graph[4][2] = 7;
primMST();
return 0; }
|
primMST()
函数实现了Prim算法的核心逻辑,它首先选择一个起点并将它的key值设置为0,然后通过循环不断选择最小key值的未访问节点,并更新与之相连的所有节点的key值。最后,程序输出最小生成树中每条边的信息及对应的权重。
Kruskal算法
Kruskal算法是另一种常用的求解加权连通图最小生成树(MST)的算法。与Prim算法不同的是,Kruskal算法关注的是边而不是顶点。它通过按权重顺序选择边来构建MST,同时确保不会形成环路。
代码实现
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
| #include <iostream> #include <vector> #include <algorithm>
using namespace std;
struct Edge { int src, dest, weight; };
struct Graph { int V, E; vector<Edge> edges; };
int find(vector<int>& subsets, int i) { if (subsets[i] == i) return i; return find(subsets, subsets[i]); }
void Union(vector<int>& subsets, int x, int y) { int xroot = find(subsets, x); int yroot = find(subsets, y); subsets[xroot] = yroot; }
bool compare(Edge e1, Edge e2) { return e1.weight < e2.weight; }
void KruskalMST(Graph& graph) { int V = graph.V; vector<Edge> result; int e = 0; sort(graph.edges.begin(), graph.edges.end(), compare);
vector<int> subsets(V); for (int v = 0; v < V; ++v) subsets[v] = v;
for (Edge next_edge : graph.edges) { int x = find(subsets, next_edge.src); int y = find(subsets, next_edge.dest);
if (x != y) { result.push_back(next_edge); Union(subsets, x, y); e++; }
if (e == V - 1) break; }
cout << "Following are the edges in the constructed MST\n"; for (Edge edge : result) cout << edge.src << " -- " << edge.dest << " == " << edge.weight << endl; }
int main() { Graph graph; graph.V = 4; graph.E = 5; graph.edges = {{0, 1, 10}, {0, 2, 6}, {0, 3, 5}, {1, 3, 15}, {2, 3, 4}};
KruskalMST(graph);
return 0; }
|
在这个例子中,我们定义了一个Graph
结构体来存储图的信息,其中包含了顶点数V
、边数E
以及边的集合edges
。每条边由源节点src
、目标节点dest
和权重weight
组成。我们还定义了两个辅助函数find
和Union
来管理并查集,这有助于检测图中的环路。
在KruskalMST
函数中,我们首先对所有的边按照权重进行排序,然后遍历这些边,使用并查集来检查加入新的边是否会形成环。如果不会形成环,则将这条边加入到结果集中,并使用Union
函数合并这两个节点所在的集合。当结果集中包含了V-1
条边时,算法结束,此时结果集即为最小生成树。
请注意,这个例子假设图是连通的。对于非连通图,Kruskal算法可以找到每个连通分量的最小生成树。
Prim和Kruskal的算法分析
