最小生成树----Kruskal算法

首先明确以下概念:
(1)连通图:无向图都有任意两个节点都能有路径相通。
(2)强连通图:有向图中任意两个节点都有路径相通。
(3)连通网:连通图中的边有权。
(4)生成树:一个连通图的生成树是指一个连通子图,含有图中全部n个顶点,仅有n-1条边,如果再添加一条边就必定成环。
(5)最小生成树:连通网中所有生成树中权值和最小的生成树。


Kruskal算法:

定义一个概念——安全边:正确的边是安全边,边的两个端点处在两个集合内的边是正确的边,就是把新的点加入到原本的集合内。

将所有的边存入并排序,每次取得权值最小的加入到sum中,每次取边之前先判断这条边的两个端点是否都在同一集合内,如果在说明已经加入过就不选这个,如果不在就要选他,选了之后要把新的点加入到集合内。执行上述操作直到遍历所有的边。

每一条边都存入一个结构体数组中。

struct edge{
    int bgn;
    int nd;
    int len;
}e[1005];

对于判断是否属于同一集合的方式我们采用“并查集”。

void init(int n){
    for(int i = 0; i <= n; i++)
        ar[i] = i;
}

int find_boss(int x){
    if(x != ar[x])
        ar[x] = find_boss(ar[x]);
    return ar[x];
}

bool same(int x, int y){
    return find_boss(x) == find_boss(y);
}

void unite(int x, int y){
    int i = find_boss(x);
    int j = find_boss(y);
    ar[j] = i;
}

完整代码如下:

#include 
#include 
#include 
using namespace std;

struct edge{
    int bgn;
    int nd;
    int len;
}e[10005];

int ar[10005];
int sum;

bool cmp(edge a, edge b){
    return a.len < b.len;
}

void init(int n){
    for(int i = 0; i <= n; i++){
        ar[i] = i;
    }
    memset(e, 0, sizeof(e));
    sum = 0;
}

int find_boss(int x){
    if(x != ar[x]){
        ar[x] = find_boss(ar[x]);
    }
    return ar[x];
}

bool same(int x, int y){
    return find_boss(x) == find_boss(y);
}

void unite(int x, int y){
    ar[find_boss(x)] = find_boss(y);
}

int main(){
    int poi_n, len_n;
    cin >> poi_n >> len_n;
    init(len_n);
    for(int i = 0; i < len_n; i++){
        cin >> e[i].bgn >> e[i].nd >> e[i].len;
    }
    sort(e, e + len_n, cmp);
    for(int i = 0; i < len_n; i++){
        if(!same(e[i].bgn, e[i].nd)){
            sum += e[i].len;
            unite(e[i].bgn, e[i].nd);
        }
    }
    cout << sum << endl;
    return 0;
}

你可能感兴趣的:(生成树)