最小生成树

Posted eimadrigal

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最小生成树相关的知识,希望对你有一定的参考价值。

一、Prim

Prim算法的思想是:

  1. 整个顶点集为(V),初始选一个起点(s),令集合(u={s}, v={})
  2. 在集合(u)与集合(V-u)中的点组成的边中,选一条权值最小的边(u_0v_0)加入MST,并且将(u_0)加入(u)
  3. 重复直到MST有(n-1)条边或(n)个顶点为止。
int adjMax[MAXN][MAXN];  //邻接矩阵

int n;   //顶点数目
int pos = 0, ans = 0;
bool visited[MAXN] = {0}, cost[MAXN];

void Prim()
{
    for (int i = 0; i < n; i++)
    {
        cost[i] = adjMax[0][i];  //集合u与集合V-u中的i点间距离最小值
        visited[i] = false;
    }

    visited[0] = true;   //已经在MST中

    for (int i = 1; i < n; i++)  //再找n-1个点
    {
        //找到连接u和V-u的最小边并记录位置
        int tmp = INT_MAX;
        for (int j = 0; j < n; j++) 
        {
            if (visited[j] == false && cost[j] < tmp)
            {
                tmp = cost[j];
                pos = j;
            }
        }

        ans += tmp;
        visited[pos] = true;

        //加入某点后,V-u中的点j到u的距离可能变短,故更新cost[j]
        for (int j = 0; j < n; j++)
        {
            if (visited[j] == false && cost[j] > adjMax[pos][j])
            {
                cost[j] = adjMax[pos][j];
            }
        }
    }
}

性能:邻接矩阵表示不依赖于边数,复杂度(O(|V|^2)),适合边稠密的图。

二、Kruskal

该算法思想:将所有边的权值递增排序,如果加入某边后不构成回路,则将该边加入MST,直到MST中有(n-1)条边或(n)个顶点:

//用结构体存储边的信息
struct edge {
    int start, des;
    int val;
}edge[MAXN];

//用并查集判断有没有环
int UFSets[MAXN];
for (int i = 0; i < n; i++)
{
    UFSets[i] = -1;
}

//在S中查找并返回包含x的树的根
int find(int S[],int x)
{
    while (S[x] >= 0)
        x = S[x];
    return x;
}

void kruskal()
{
    for (int i = 0; i < m; i++)
    {
        int u = find(UFSets, edge[i].start);
        int v = find(UFSets, edge[i].des);

        if (u == v)  //edge[i]的两端点有相同的祖先,成环
            continue;

        ans += edge[i].val;
        UFSets[u] = v;  //合并两个并查集
        cnt++;

        if (cnt == n - 1)
            break;
    }
}

性能:复杂度(O(ElogE)),适合边稀疏、顶点多的图。

以上是关于最小生成树的主要内容,如果未能解决你的问题,请参考以下文章

最小生成树matlab代码Kruskal算法,用于二维网络生成

c语言最小生成树

最小生成树及Prim算法及Kruskal算法的代码实现

数据结构 图连通与最小生成树

次最小生成树 模版

图的最小生成树算法(图解+代码)| 学不会来看我系列