1. 程式人生 > >圖的最小生成樹Kruskal演算法樸素版(C++)

圖的最小生成樹Kruskal演算法樸素版(C++)

Kruskal演算法先將所有的邊按權值由小到大排序,然後從無開始(即每個頂點都是一棵子樹),每次選取權值最小不會構成迴路的邊作為最終最小生成樹的一部分。最終能夠將多個不連通的子樹聯合起來構成最小生成樹。

時間複雜度為O(ElogE+V2)。E為圖中的邊數,V為圖中頂點數。

C++程式碼如下:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

typedef int DATA_TYPE;  // 權值為int型
const DATA_TYPE NO_EDGE = 10000000
; // 表示沒有該邊 // 鄰接矩陣 struct AdjMatrixGraph { vector<vector<DATA_TYPE> > weights; }; // 邊和權值的配對 <<頭結點,尾結點>,權值> typedef pair<vector<int>, DATA_TYPE> PAIR; int comp(const PAIR &x, const PAIR &y) { return x.second < y.second; } vector<vector<int>
>
Kruskal(AdjMatrixGraph graph) { vector<vector<int> > MST; // 最小生成樹邊結果集合 int vertexNum = graph.weights.size(); // 頂點總數 vector<int> setNum; // 每個頂點所屬的子樹編號 vector<PAIR> edgesAndWeights; // 邊和權值配對的向量(便於按值排序) for (int i = 0; i < vertexNum; ++i) { for
(int j = 0; j < vertexNum; ++j) { if (graph.weights[i][j] > 0 && graph.weights[i][j] < NO_EDGE) { // 獲取每一條邊的資訊 edgesAndWeights.push_back(make_pair(vector<int>{i, j}, graph.weights[i][j])); } } setNum.push_back(i); // 初始化每一個頂點都分屬不同的子樹 } // 對每一條邊按權值升序排序 sort(edgesAndWeights.begin(), edgesAndWeights.end(), comp); int k = 1; // 當前正在構造第幾條邊 // 最小生成樹總共有vertexNum-1條邊 for (vector<PAIR>::iterator mapIter = edgesAndWeights.begin(); mapIter != edgesAndWeights.end(); ++mapIter) { int headSet = setNum[mapIter->first[0]]; // 當前邊的頭結點所屬的子樹編號 int tailSet = setNum[mapIter->first[1]]; // 當前邊的尾結點所屬的子樹編號 // 如果它們分屬不同的子樹(即連線之後不構成迴路),則選擇該邊 if (headSet != tailSet) { MST.push_back(mapIter->first); ++k; // 更新頂點的所屬子樹的編號 for (int i = 0; i < vertexNum; ++i) { if (setNum[i] == tailSet) { setNum[i] = headSet; } } } if (k >= vertexNum) { break; } } return MST; } int main(int argc, char *argv[]) { // 圖鄰接矩陣 // 編號從0開始 若不是先轉換 AdjMatrixGraph graph; graph.weights.push_back(vector<DATA_TYPE>{0, 6, 1, 5, NO_EDGE, NO_EDGE}); graph.weights.push_back(vector<DATA_TYPE>{6, 0, 5, NO_EDGE, 3, NO_EDGE}); graph.weights.push_back(vector<DATA_TYPE>{1, 5, 0, 5, 6, 4}); graph.weights.push_back(vector<DATA_TYPE>{5, NO_EDGE, 5, 0, NO_EDGE, 2}); graph.weights.push_back(vector<DATA_TYPE>{NO_EDGE, 3, 6, NO_EDGE, 0, 6}); graph.weights.push_back(vector<DATA_TYPE>{NO_EDGE, NO_EDGE, 4, 2, 6, 0}); vector<vector<int> > MST = Kruskal(graph); for (size_t i = 0; i < MST.size(); ++i) { cout <<"邊(" << MST[i][0] << " " << MST[i][1] << ") || 權值: " << graph.weights[MST[i][0]][MST[i][1]] << endl; } return 0; }

測試用例圖如下:
這裡寫圖片描述

輸出結果:
邊(0 2) || 權值: 1
邊(5 3) || 權值: 2
邊(4 1) || 權值: 3
邊(2 5) || 權值: 4
邊(2 1) || 權值: 5