最小生成树(贪心思想)

最小生成树是一个连通加权无向图中一棵权值最小的生成树。

Prim算法思想:
设图G顶点集合为U,首先任意选择图G中的一点作为起始点a,将该点加入集合V,再从集合U-V中找到另一点b使得点b到V中任意一点的权值最小,此时将b点也加入集合V;以此类推,现在的集合V={a,b},再从集合U-V中找到另一点c使得点c到V中任意一点的权值最小,此时将c点加入集合V,直至所有顶点全部被加入V,此时就构建出了一棵MST(Minimum Spanning Tree,最小生成树)。因为有N个顶点,所以该MST就有N-1条边,每一次向集合V中加入一个点,就意味着找到一条MST的边。
代码实现:

//最小生成树
int map[N][N]; //存i到j的路径
int vis[N]; //存该节点是否已经选取过了
int dist[N];  //树到其它各个节点的距离

int prim()
{
    int sum =0;
    for(int i=0;i<n;i++)
        dist[i]= map[0][i];
    vis[0]=true;
    for(int i=1;i<=n-1;i++) //找n-1条边
    {
        int minn=INT_MAX;
        int index=0;
        for(int j=0;j<n;j++) //找当前树到其它节点的最短路径加入树
        {
            if(vis[j]==false&&dist[j]<minn)
            {
                minn=dist[j];
                index=j;
            }
        }
        sum+=minn;
        vis[index]=true;
        for(int j=0;j<n;j++) //更新树到树外其它节点的最小距离
        {
            if(vis[j]==false&&dist[j]>map[index][j])
                dist[j]=map[index][j];
        }
    }
    return sum;

}

时间复杂度:O(n^2)

Kruskal算法思想:
Kruskal算法是基于贪心的思想得到的。首先我们把所有的边按照权值先从小到大排列,接着按照顺序选取每条边,如果这条边的两个端点不属于同一集合,那么就将它们合并,直到所有的点都属于同一个集合为止。至于怎么合并到一个集合,需要使用并查集。换而言之,Kruskal算法就是基于并查集的贪心算法。
基本思想是以边为主导地位,始终都是选择当前可用的最小权值的边,步骤如下:

  1. 设一个有n个顶点的连通网络为G(V,E),最初先构造一个只有n个顶点,没有边的非连通图T(V,Ø),图中每个顶点自成一个连通分量
  2. 将原图中的所有边按权值从小到大排序
  3. 从权值最小的边开始,如果这条边连接的两个顶点于图T中不在同一个连通分量中,则添加这条边到图T中
  4. 重复3,直至T中所有顶点在同一个连通分量中为止
    代码实现:
#include <iostream>
#include<algorithm>
#include<cstdio>
using namespace std;

#define maxn 110; //最多点个数
int fa[110]; //并查集存根节点
int n, m; //顶点个数, 边数

struct Edge{
    int x, y;
    int val;
}edge[5000];

bool cmp(Edge a, Edge b)
{
    return a.val < b.val;
}

int findfa(int x)  //寻找所在树的根节点,判断是否在同一个连同分量的依据
{
    if(fa[x] != x)
        fa[x] = findfa(fa[x]);
    return fa[x];
    //return fa[x] == x ? x : (fa[x] = findfa(fa[x]));
}

int Union(int x, int y)  //并查集合并两棵树
{
    fa[findfa(x)] = findfa(y);
}

int Kruskal()
{
    int cnt = 0;
    long sum = 0;

    for(int i=1; i<=n; i++)  //顶点的编号为[1..n]
        fa[i] = i;
    sort(edge, edge+m, cmp);  //把边从小到大排序,m为边的数目

    for(int i=0; i<m; i++)
    {
        int fx = findfa(edge[i].x);
        int fy = findfa(edge[i].y);
        if(fx != fy)
        {
            Union(fx, fy);
            cnt++;
            sum += edge[i].val;
            if(cnt >= n-1) break;   //n-1条边均加入同一个集合中
        }
    }
    return sum;
}

int main()
{
    cin>>n>>m;

    for(int i=0; i<m; i++)
        cin>>edge[i].x>>edge[i].y>>edge[i].val;
    cout<<Kruskal()<<endl;

    return 0;
}

/*
5 7
1 2 3
1 5 1
2 5 4
2 3 5
3 4 2
3 5 6
4 5 7
*/

时间复杂度: O(E*logE)
Kruskal算法每次要从都要从剩余的边中选取一个最小的边。通常我们要先对边按权值从小到大排序,这一步的时间复杂度为为O(ElogE)。Kruskal算法的实现通常使用并查集,来快速判断两个顶点是否属于同一个集合。最坏的情况可能要枚举完所有的边,此时要循环E次,所以这一步的时间复杂度为O(Eα(V)),其中α为Ackermann函数,其增长非常慢,我们可以视为常数。所以Kruskal算法的时间复杂度为O(ElogE)。

总结:
Prim和Kruskal的贪心策略是一样的,都是选取耗费最小的边:

  • 对于Prim, 其选取的边(u,v)必有一个顶点已经被覆盖,另一个顶点未被覆盖,适用于稠密图。
  • 对于Kruskal, 其选取的边(u,v)任意,只要这个边的加入不会使被覆盖的顶点构成回路,适用于稀疏图。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容