如何使用C++中的最小生成樹算法
最小生成樹(Minimum Spanning Tree,MST)是圖論中一個重要的概念,它表示連接一個無向連通圖的所有頂點的邊的子集,且這些邊的權值之和最小。有多種算法可以用來求解最小生成樹,如Prim算法和Kruskal算法。本文將介紹如何使用C++實現Prim算法和Kruskal算法,并給出具體的代碼示例。
Prim算法是一種貪心算法,它從圖的一個頂點開始,逐步選擇與當前最小生成樹連接的權值最小的邊,并將該邊加入到最小生成樹中。以下是Prim算法的C++代碼示例:
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int INF = 1e9;
int prim(vector<vector<pair<int, int>>>& graph) {
int n = graph.size(); // 圖的頂點數
vector<bool> visited(n, false); // 標記頂點是否已訪問
vector<int> dist(n, INF); // 記錄頂點到最小生成樹的最短距離
int minCost = 0; // 最小生成樹的總權值
// 從第一個頂點開始構建最小生成樹
dist[0] = 0;
// 使用優先隊列保存當前距離最小的頂點和權值
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
pq.push(make_pair(0, 0));
while (!pq.empty()) {
int u = pq.top().second; // 當前距離最小的頂點
pq.pop();
// 如果頂點已訪問過,跳過
if (visited[u]) {
continue;
}
visited[u] = true; // 標記頂點為已訪問
minCost += dist[u]; // 加入頂點到最小生成樹的權值
// 對于頂點u的所有鄰接頂點v
for (auto& edge : graph[u]) {
int v = edge.first;
int weight = edge.second;
// 如果頂點v未訪問過,并且到頂點v的距離更小
if (!visited[v] && weight < dist[v]) {
dist[v] = weight;
pq.push(make_pair(dist[v], v));
}
}
}
return minCost;
}
int main() {
int n, m; // 頂點數和邊數
cin >> n >> m;
vector<vector<pair<int, int>>> graph(n);
// 讀取邊的信息
for (int i = 0; i < m; ++i) {
int u, v, w; // 邊的兩個頂點及其權值
cin >> u >> v >> w;
--u; --v; // 頂點從0開始編號
graph[u].push_back(make_pair(v, w));
graph[v].push_back(make_pair(u, w));
}
int minCost = prim(graph);
cout << "最小生成樹的權值之和為:" << minCost << endl;
return 0;
}
登錄后復制
Kruskal算法是一種基于邊的貪心算法,它從圖的所有邊中選擇權值最小的邊,并判斷該邊是否會形成環路。如果不會形成環路,則將該邊加入到最小生成樹中。以下是Kruskal算法的C++代碼示例:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct Edge {
int u, v, weight; // 邊的兩個頂點及其權值
Edge(int u, int v, int weight) : u(u), v(v), weight(weight) {}
};
const int MAXN = 100; // 最大頂點數
int parent[MAXN]; // 并查集數組
bool compare(Edge a, Edge b) {
return a.weight < b.weight;
}
int findParent(int x) {
if (parent[x] == x) {
return x;
}
return parent[x] = findParent(parent[x]);
}
void unionSet(int x, int y) {
int xParent = findParent(x);
int yParent = findParent(y);
if (xParent != yParent) {
parent[yParent] = xParent;
}
}
int kruskal(vector<Edge>& edges, int n) {
sort(edges.begin(), edges.end(), compare);
int minCost = 0; // 最小生成樹的總權值
for (int i = 0; i < n; ++i) {
parent[i] = i; // 初始化并查集數組
}
for (auto& edge : edges) {
int u = edge.u;
int v = edge.v;
int weight = edge.weight;
// 如果頂點u和頂點v不屬于同一個連通分量,則將該邊加入到最小生成樹中
if (findParent(u) != findParent(v)) {
unionSet(u, v);
minCost += weight;
}
}
return minCost;
}
int main() {
int n, m; // 頂點數和邊數
cin >> n >> m;
vector<Edge> edges;
// 讀取邊的信息
for (int i = 0; i < m; ++i) {
int u, v, w; // 邊的兩個頂點及其權值
cin >> u >> v >> w;
edges.push_back(Edge(u, v, w));
}
int minCost = kruskal(edges, n);
cout << "最小生成樹的權值之和為:" << minCost << endl;
return 0;
}
登錄后復制
通過以上代碼示例,我們可以在C++中使用Prim算法和Kruskal算法求解最小生成樹的問題。在實際應用中,可以根據具體情況選擇合適的算法來解決問題。這些算法的時間復雜度分別為O(ElogV)和O(ElogE),其中V為頂點數,E為邊數。因此,它們在處理大規模圖的情況下也能夠得到較好的效果。
以上就是如何使用C++中的最小生成樹算法的詳細內容,更多請關注www.xfxf.net其它相關文章!






