【最小生成树之Kruskal算法】

我的未来我决定 提交于 2020-02-13 14:10:20
看完之后推荐再看一看【最小生成树之Prim算法】-C++

定义:一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。最小生成树可以用kruskal(克鲁斯卡尔)算法或Prim(普里姆)算法求出。 。
​在一给定的无向图G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边(即),而 w(u, v) 代表此边的权重,若存在 T 为 E 的子集(即)且为无循环图,使得

的 w(T) 最小,则此 T 为 G 的最小生成树。

最小生成树其实是最小权重生成树的简称。

许多应用问题都是一个求无向连通图的最小生成树问题。例如:要在n个城市之间铺设光缆,主要目标是要使这 n 个城市的任意两个之间都可以通信,但铺设光缆的费用很高,且各个城市之间铺设光缆的费用不同;另一个目标是要使铺设光缆的总费用最低。这就需要找到带权的最小生成树。

这一章主要介绍Kruskal算法。

Kruskal算法的时间复杂度:O(m*log(n))(点数n边数m)

主要思路:

输入之后对边权值进行排序,然后按边权值从小到大进行合并(merge)操作,如果操作成功(被合并的两个点不在一棵树上),则把这两个顶点的边权值加入总数,最后输出total即可。
主要使用:

“并查集。”

洛谷P3366【模板】最小生成树
这道题我第一次是用Kruskal来写的,具体思路再讲解一下。
首先把get和merge函数写好,为了方便,我把merge写成了bool类型:如果成功合并(要求合并的两个顶点不在一棵树上)就返回true。
然后是最正常的运用结构体进行循环读入,读入完成之后写cmp排序函数按边权值从小到大进行排序。
接下来才和并查集扯上关系,所以要重新定义fa数组,然后进行初始化;

核心代码

	int cnt=0;
    int total=0;
    for(int i=1;i<=p;i++)//p为边数
    {
        if(merge(mp[i].u,mp[i].v))
        {
            cnt++;
            total+=mp[i].w;
            if(cnt==p-1) break;
        }
    }

这段代码主要是为了统计权值和。把权值从最小到最大跑一遍,如果能够合并就合并然后加进total即可。然后就没什么难的了emm。
下面贴代码;

参考代码:

#include<bits/stdc++.h>
using namespace std;
struct noded
{
    int u,v;
    int w;
    noded(){}
    noded(int uu,int vv,int ww)
    {
        u=uu,v=vv,w=ww;
    }
}mp[200010];
bool cmp(noded x,noded y)
{
    return x.w<y.w;
}
int fa[5010];
int get(int x)
{
    if(fa[x]==x)return x;
    else
    {
        fa[x]=get(fa[x]);
        return fa[x];
    }
}
bool merge(int x,int y)
{
    int r1=get(x),r2=get(y);
    if(r1!=r2)
    {
        fa[r1]=r2;
        return true;
    }
    else return false;
}
int ans[250010];
void init()
{
    for(int i=1;i<=5000;i++)
    {
        fa[i]=i;
    }
}
int main()
{
    //sqrt(pow((x1-x2),2)+pow((y1-y2),2));
    int n,p;
    cin>>n>>p;
    for(int i=1;i<=p;i++)
    {
        cin>>mp[i].u>>mp[i].v>>mp[i].w;
    }
    sort(mp+1,mp+1+p,cmp);
    //for(int i=1;i<=k;i++)
    //{
    //  cout<<endl<<mp[i].w;
    //}
    init();
    int cnt=0;
    int total=0;
    for(int i=1;i<=p;i++)
    {
        if(merge(mp[i].u,mp[i].v))
        {
            cnt++;
            total+=mp[i].w;
            if(cnt==p-1) break;
        }
    }
    cout<<total<<endl;
    return 0;
}

ov.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!