克鲁斯卡尔算法小结(使用查并集)

克鲁斯卡尔算法 最小生成树

1.基本思想

先构造一个只含 n 个顶点、而边集为空的子图,把子图中各个顶点看成各棵树上的根结点,之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,即把两棵树合成一棵树,反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直到森林中只有一棵树,也即子图中含有 n-1 条边为止

2.使用查并集算法

并查集就是把每堆元素合并为一个具有相同父节点的集合,如果两堆元素父节点不同,说明他们不连通,反之连通

int pre[N];

void init(int n)
{
    for(int i=0;i<n;i++)
        pre[i]=i;
}
//初始化函数  使得每个节点的父节点为其本身
//即 各个节点独立

int find(int x)
{
    int r=x,i=x,temp;
   
    if(pre[r]==r)
        return r;
    
    while(pre[r]!=r)
        r=pre[r];
    
    while(i!=r)
    {
        temp=pre[i];
        pre[i]=r;
        i=temp;
    }
    //进行路径压缩
    return r;
}

3.克鲁斯卡尔算法

#include
using namespace std;

struct Edge
{
    int u,v,w;
}
const int max=100000+10;

int pre[max];
Edge edge[max];

bool compare(Edge e1,Edge e2)
{
    return e1.w<e2.w;
}
void init(int n)
{
    for(int i=0;i<n;i++)
        pre[i]=i;
}
//初始化函数  使得每个节点的父节点为其本身
//即 各个节点独立

int find(int x)
{
    int r=x,i=x,temp;
   
    if(pre[r]==r)
        return r;
    
    while(pre[r]!=r)
        r=pre[r];
    
    while(i!=r)
    {
        temp=pre[i];
        pre[i]=r;
        i=temp;
    }
    //进行路径压缩
    return r;
}
//找到其父节点

void Kruskal(int n)
{
    int i,sum,total,fx,fy;
    total = 1;
    sum = 0;
    i = 0;
    
    while(total<n)
    {
        fx = find(edge[i].u);
        fy = find(edge[i].v);
        if(fx!=fy)
        {
            pre[fx] = fy;
            total++;
            sum +=edge[i].w;
            //最小生成树所有边之和
        }
        //判断是否形成环 
        //fx == fy 则现在是有一个环 ,因此要寻找下一条边
        i++;
    }
    cout<<sum;
}

int main()
{
    int n,m;
    int i,x,y,z;
    cin>>n>>m;
    
    for(i=0;i<m;i++)
    {
        cin>>edge[i].u;
        cin>>edge[i].v;
        cin>>edge[i].w;
    }
    sort(edge,edge+m,compare);
    init(n);
    
    Kruskal(n);
}

4.小结

  1. 在克鲁斯卡尔算法中,从最小边开始,依次判断新加一条边是否满足要求 即 不能形成环

  2. 判断是否有环 则需要 边的结构体查并集(包含压缩算法) 结合使用

  3. 使用 sort函数 并且 指定第三个参数 来对 边 从小到大排序

  4. 若该边满足条件,则加上该条边长度,最后输出 sum

你可能感兴趣的:(克鲁斯卡尔算法小结(使用查并集))