圖的最小生成樹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


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com