转载

克鲁斯卡尔算法

克鲁斯卡尔算法

基本思想

先构造一个只含 n 个顶点、而边集为空的子图,把子图中各个顶点看成各棵树上的根结点,之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,即把两棵树合成一棵树,反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直到森林中只有一棵树,也即子图中含有 n-1 条边为止。时间复杂度为为O(e^2), 使用并查集优化后复杂度为 O(eloge),与网中的边数有关,适用于求边稀疏的网的最小生成树。

例图

C++代码

#include<iostream>
#include<climits>
using namespace std;
#define size 11

char change(int i) {
    switch(i){
        case 0: return 'A';
        case 1: return 'B';
        case 2: return 'C';
        case 3: return 'D';
        case 4: return 'E';
        case 5: return 'F';
        case 6: return 'G'; 
    }
    return 'O';
}

int a[7][7] = {
    {0, 7, INT_MAX, 5, INT_MAX, INT_MAX, INT_MAX},
    {7, 0, 8, 9, 7, INT_MAX, INT_MAX},
    {INT_MAX, 8, 0, INT_MAX, 5, INT_MAX, INT_MAX},
    {5, 9, INT_MAX, 0, 15, 6, INT_MAX},
    {INT_MAX, 7, 5, 15, 0, 8, 9},
    {INT_MAX, INT_MAX, INT_MAX, 6, 8, 0, 11},
    {INT_MAX, INT_MAX, INT_MAX, INT_MAX, 9, 11, 0}
};

/*并查集*/
int visited[7] = {0, 1, 2, 3, 4, 5, 6};

typedef struct{
    int start;
    int end;
    int len;
}Edge;

/*并查集*/
int Find(int x) {
    if(visited[x] != x) visited[x] = Find(visited[x]);
    return visited[x];
}

void Union(int x, int y){
    int xParent = Find(x);
    int yParent = Find(y);
    if(xParent == yParent) return;

    visited[yParent] = xParent; 
}

int main() {
    Edge edge[size];
    int time = 0;
    for(int i = 0; i < 7; i++) 
        for(int j = 0; j < i; j++) {
            if(a[i][j] == INT_MAX) continue;
            edge[time].start = i;
            edge[time].end = j;
            edge[time].len = a[i][j];
            time++;
        }

    /*插入排序*/
    for(int i = 1; i < size; i++) {
        Edge key = edge[i];
        while(i > 0 && edge[i-1].len > key.len) {
            edge[i] = edge[i-1];
            i--;
        }
        edge[i] = key;
    } 

    int n = 6, count = 0, index = 0;
    while(true) {
        int x = edge[index].start;
        int y = edge[index].end;
        int len = edge[index].len;
        int xParent = Find(x);
        int yParent = Find(y);

        index++;
        if(xParent == yParent) {
            continue;
        }else{
            Union(x, y);
            count += len;
            cout << "第" << 7 - n << "条边: " << change(x) << "->" << change(y) << endl;
            n--;
        }
        if(n == 0) break;
    }
    cout << "最小生成树长度: " << count << endl; 
} 
/* 第1条边: D->A 第2条边: E->C 第3条边: F->D 第4条边: B->A 第5条边: E->B 第6条边: G->E 最小生成树长度: 39 */

相关普里姆算法

正文到此结束
本文目录