在圖論中,尋找連通加權圖的最小生成樹(MST)是一個常見的問題。 MST是圖的邊的子集,它連接了所有的頂點並最小化了總邊權。解決這個問題的一個高效率演算法是Boruvka演算法。
文法
struct Edge { int src, dest, weight; }; // Define the structure to represent a subset for union-find struct Subset { int parent, rank; };
演算法
現在,讓我們概述Boruvka演算法中涉及的尋找最小生成樹的步驟−
將 MST 初始化為空集。
為每個頂點建立一個子集,其中每個子集只包含一個頂點。
-
重複以下步驟,直到最小生成樹(MST)有V-1條邊(V是圖中頂點的數量)−
對於每個子集,找到將其連接到另一個子集的最便宜的邊。
將選定的邊加入到最小生成樹。
對所選邊的子集執行並集操作。
輸出最小生成樹。
方法
在Boruvka演算法中,有多種方法可以找到連接每個子集的最便宜的邊。以下是兩種常見的方法−
方法一:樸素方法
對於每個子集,遍歷所有邊,並找到將其連接到另一個子集的最小邊。
追蹤選定的邊並執行聯合操作。
範例
#include <iostream> #include <vector> #include <algorithm> struct Edge { int src, dest, weight; }; // Define the structure to represent a subset for union-find struct Subset { int parent, rank; }; // Function to find the subset of an element using path compression int find(Subset subsets[], int i) { if (subsets[i].parent != i) subsets[i].parent = find(subsets, subsets[i].parent); return subsets[i].parent; } // Function to perform union of two subsets using union by rank void unionSets(Subset subsets[], int x, int y) { int xroot = find(subsets, x); int yroot = find(subsets, y); if (subsets[xroot].rank < subsets[yroot].rank) subsets[xroot].parent = yroot; else if (subsets[xroot].rank > subsets[yroot].rank) subsets[yroot].parent = xroot; else { subsets[yroot].parent = xroot; subsets[xroot].rank++; } } // Function to find the minimum spanning tree using Boruvka's algorithm void boruvkaMST(std::vector<Edge>& edges, int V) { std::vector<Edge> selectedEdges; // Stores the edges of the MST Subset* subsets = new Subset[V]; int* cheapest = new int[V]; // Initialize subsets and cheapest arrays for (int v = 0; v < V; v++) { subsets[v].parent = v; subsets[v].rank = 0; cheapest[v] = -1; } int numTrees = V; int MSTWeight = 0; // Keep combining components until all components are in one tree while (numTrees > 1) { for (int i = 0; i < edges.size(); i++) { int set1 = find(subsets, edges[i].src); int set2 = find(subsets, edges[i].dest); if (set1 != set2) { if (cheapest[set1] == -1 || edges[cheapest[set1]].weight > edges[i].weight) cheapest[set1] = i; if (cheapest[set2] == -1 || edges[cheapest[set2]].weight > edges[i].weight) cheapest[set2] = i; } } for (int v = 0; v < V; v++) { if (cheapest[v] != -1) { int set1 = find(subsets, edges[cheapest[v]].src); int set2 = find(subsets, edges[cheapest[v]].dest); if (set1 != set2) { selectedEdges.push_back(edges[cheapest[v]]); MSTWeight += edges[cheapest[v]].weight; unionSets(subsets, set1, set2); numTrees--; } cheapest[v] = -1; } } } // Output the MST weight and edges std::cout << "Minimum Spanning Tree Weight: " << MSTWeight << std::endl; std::cout << "Selected Edges:" << std::endl; for (const auto& edge : selectedEdges) { std::cout << edge.src << " -- " << edge.dest << " \tWeight: " << edge.weight << std::endl; } delete[] subsets; delete[] cheapest; } int main() { // Pre-defined input for testing purposes int V = 6; int E = 9; std::vector<Edge> edges = { {0, 1, 4}, {0, 2, 3}, {1, 2, 1}, {1, 3, 2}, {1, 4, 3}, {2, 3, 4}, {3, 4, 2}, {4, 5, 1}, {2, 5, 5} }; boruvkaMST(edges, V); return 0; }
輸出
Minimum Spanning Tree Weight: 9 Selected Edges: 0 -- 2 Weight: 3 1 -- 2 Weight: 1 1 -- 3 Weight: 2 4 -- 5 Weight: 1 3 -- 4 Weight: 2
Explanation
的中文翻譯為:解釋
我們先定義兩個結構 - Edge 和 Subset。 Edge 表示圖中的一邊,包含邊的來源、目的地和權重。 Subset表示並檢查資料結構的子集,包含父級和排名資訊。
find函數是一個輔助函數,它使用路徑壓縮來尋找元素的子集。它遞歸地查找元素所屬的子集的代表(父節點),並壓縮路徑以優化未來的查詢。
unionSets函數是另一個輔助函數,使用按秩合併的方式對兩個子集進行合併。它找到兩個子集的代表,並根據秩進行合併,以保持平衡樹。
boruvkaMST 函數採用邊向量和頂點數 (V) 作為輸入。它實作了 Boruvka 演算法來查找 MST。
在 boruvkaMST 函數內,我們建立一個向量 selectedEdges 來儲存 MST 的邊。
我們建立一個Subset結構的陣列來表示子集,並用預設值初始化它們。
我們也建立了一個陣列 cheapest 來追蹤每個子集的最便宜的邊。
變數 numTrees 被初始化為頂點的數量,MSTWeight 被初始化為 0。
該演算法透過重複組合組件來進行,直到所有組件都在一棵樹中。主循環運行直到 numTrees 變為 1。
在主循環的每次迭代中,我們迭代所有邊並找到每個子集的最小加權邊。如果邊連接兩個不同的子集,我們用最小加權邊的索引來更新最便宜的陣列。
接下來,我們遍歷所有的子集,如果一個子集存在最小權重的邊,我們將其添加到selectedEdges向量中,更新MSTWeight,執行子集的並集操作,並減少numTrees的值。
最後,我們輸出 MST 權重和選定的邊。
主要功能提示使用者輸入頂點數和邊數。然後,它會取得每條邊的輸入(來源、目標、權重)並使用輸入呼叫 boruvkaMST 函數。
方法二:使用優先隊列
建立一個依照權重排序的優先權佇列來儲存邊。
對於每個子集,從優先權佇列中找到將其連接到另一個子集的最小權重邊。
追蹤選定的邊並執行聯合操作。
範例
#include <iostream> #include <vector> #include <queue> #include <climits> using namespace std; // Edge structure representing a weighted edge in the graph struct Edge { int destination; int weight; Edge(int dest, int w) : destination(dest), weight(w) {} }; // Function to find the shortest path using Dijkstra's algorithm vector<int> dijkstra(const vector<vector<Edge>>& graph, int source) { int numVertices = graph.size(); vector<int> dist(numVertices, INT_MAX); vector<bool> visited(numVertices, false); dist[source] = 0; priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq; pq.push(make_pair(0, source)); while (!pq.empty()) { int u = pq.top().second; pq.pop(); if (visited[u]) { continue; } visited[u] = true; for (const Edge& edge : graph[u]) { int v = edge.destination; int weight = edge.weight; if (dist[u] + weight < dist[v]) { dist[v] = dist[u] + weight; pq.push(make_pair(dist[v], v)); } } } return dist; } int main() { int numVertices = 4; vector<vector<Edge>> graph(numVertices); // Adding edges to the graph graph[0].push_back(Edge(1, 2)); graph[0].push_back(Edge(2, 5)); graph[1].push_back(Edge(2, 1)); graph[1].push_back(Edge(3, 7)); graph[2].push_back(Edge(3, 3)); int source = 0; vector<int> shortestDistances = dijkstra(graph, source); cout << "Shortest distances from source vertex " << source << ":\n"; for (int i = 0; i < numVertices; i++) { cout << "Vertex " << i << ": " << shortestDistances[i] << endl; } return 0; }
輸出
Shortest distances from source vertex 0: Vertex 0: 0 Vertex 1: 2 Vertex 2: 3 Vertex 3: 6
Explanation
的中文翻譯為:解釋
在這個方法中,我們使用優先權佇列來最佳化尋找每個子集的最小加權邊的過程。下面是程式碼的詳細解釋 −
程式碼結構和輔助函數(如find和unionSets)與先前的方法保持相同。
boruvkaMST 函數被修改為使用優先權佇列來有效地找到每個子集的最小加權邊。
而不是使用最便宜的數組,我們現在創建一個邊的優先隊列(pq)。我們用圖的邊來初始化它。
主循環運行直到 numTrees 變成 1,與先前的方法類似。
在每次迭代中,我們從優先隊列中提取最小權重的邊(minEdge)。
然後我們使用find函數找到minEdge的來源和目標所屬的子集。
如果子集不同,我們將minEdge加入到selectedEdges向量中,更新MSTWeight,執行子集的合併,並減少numTrees。
這個過程將繼續,直到所有組件都在一棵樹中。
最後,我們輸出 MST 權重和選定的邊。
主要功能與先前的方法相同,我們有預先定義的輸入用於測試目的。
結論
Boruvka 演算法為尋找加權圖的最小生成樹提供了一個有效的解決方案。在用 C 實作演算法時,我們的團隊深入探索了兩種不同的路徑:一種是傳統的或「樸素」的方法。另一個利用優先權隊列。取決於當前給定問題的具體要求。每種方法都有一定的優點,可以相應地實施。透過理解和實作 Boruvka 演算法,您可以有效地解決 C 專案中的最小生成樹問題。
以上是C++中的Boruvka演算法用於最小生成樹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

從XML轉換到C 並進行數據操作可以通過以下步驟實現:1)使用tinyxml2庫解析XML文件,2)將數據映射到C 的數據結構中,3)使用C 標準庫如std::vector進行數據操作。通過這些步驟,可以高效地處理和操作從XML轉換過來的數據。

C#使用自動垃圾回收機制,而C 採用手動內存管理。 1.C#的垃圾回收器自動管理內存,減少內存洩漏風險,但可能導致性能下降。 2.C 提供靈活的內存控制,適合需要精細管理的應用,但需謹慎處理以避免內存洩漏。

C 在現代編程中仍然具有重要相關性。 1)高性能和硬件直接操作能力使其在遊戲開發、嵌入式系統和高性能計算等領域佔據首選地位。 2)豐富的編程範式和現代特性如智能指針和模板編程增強了其靈活性和效率,儘管學習曲線陡峭,但其強大功能使其在今天的編程生態中依然重要。

C 學習者和開發者可以從StackOverflow、Reddit的r/cpp社區、Coursera和edX的課程、GitHub上的開源項目、專業諮詢服務以及CppCon等會議中獲得資源和支持。 1.StackOverflow提供技術問題的解答;2.Reddit的r/cpp社區分享最新資訊;3.Coursera和edX提供正式的C 課程;4.GitHub上的開源項目如LLVM和Boost提陞技能;5.專業諮詢服務如JetBrains和Perforce提供技術支持;6.CppCon等會議有助於職業

C#適合需要高開發效率和跨平台支持的項目,而C 適用於需要高性能和底層控制的應用。 1)C#簡化開發,提供垃圾回收和豐富類庫,適合企業級應用。 2)C 允許直接內存操作,適用於遊戲開發和高性能計算。

C 持續使用的理由包括其高性能、廣泛應用和不斷演進的特性。 1)高效性能:通過直接操作內存和硬件,C 在系統編程和高性能計算中表現出色。 2)廣泛應用:在遊戲開發、嵌入式系統等領域大放異彩。 3)不斷演進:自1983年發布以來,C 持續增加新特性,保持其競爭力。

C 和XML的未來發展趨勢分別為:1)C 將通過C 20和C 23標準引入模塊、概念和協程等新特性,提升編程效率和安全性;2)XML將繼續在數據交換和配置文件中佔據重要地位,但會面臨JSON和YAML的挑戰,並朝著更簡潔和易解析的方向發展,如XMLSchema1.1和XPath3.1的改進。

現代C 設計模式利用C 11及以後的新特性實現,幫助構建更靈活、高效的軟件。 1)使用lambda表達式和std::function簡化觀察者模式。 2)通過移動語義和完美轉發優化性能。 3)智能指針確保類型安全和資源管理。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SublimeText3 Linux新版
SublimeText3 Linux最新版

Dreamweaver CS6
視覺化網頁開發工具

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。