最小生成树

1. 生成树:将图删去一些边变成树。假定图有n个点,m条边,那么需要删掉m-(n-1)条边。

2. 最小生成树:指生成树中权值之和最小的树。

3. 最小生成树算法有两种:(Kruskal算法必须掌握)

   a. Prim算法:其算法复杂度为O(n*n),其算法思想与Dijkstra算法类似,第一步选最小,第二部标记,第三步更新。Prim算法和Dijkistra算法的区别在于的 d [ i ] 的含义不同:在Dijkistra算法中,含义是从起点到第i个点的长度,在Prim算法中,含义是与第i个结点相连的边的最短长度(没有被别人提前占用)。

   b. Kruskal算法:其算法复杂度为O(nlogn),其算法核心思想是依次加边法,其核心技术排序(quick sort,按边的权值进行排序)和并查集(判断是否构成环)

4. 实例

 5. 代码:

#include <bits/stdc++.h>
using namespace std;
//定义边的属性
struct Edge
{
    int u, v, w;//边的起点,终点和权值
    Edge(int _u, int _v, int _w):u(_u), v(_v),w(_w) {}
    Edge() {}
};
Edge e[200005];

int father[5005];//并查集,父亲表示法,父亲相同表示他们在同一集合
//并查集的查找函数
int Find(int x)//查找x的父亲
{
    if(father[x]==x)//找到根节点
    {
        return x;
    }
    else
    {
        father[x]=Find(father[x]);//递归,x的父亲=他的祖先
        return father[x];
    }
}

//定义排序规则,按边的权值从小到大排
bool comp(const Edge &a,const Edge &b)
{
    if(a.w<b.w)//表示从小到大排
    {
        return true;
    }
    return false;
}

int main()
{
    int n, m;//n点数,m边数
    cin>>n>>m;
    //并查集初始化
    for(int i=0; i<n; i++)
    {
        father[i]=i;
    }
    //读取边的信息
    for(int i=0; i<m; i++)
    {
        int x, y, z;
        cin>>x>>y>>z;
        e[i]=Edge(x,y,z);
    }
    //按权值大小对边进行排序
    sort(e, e+m, comp);

    int k=0, tot=0;
    //Kruskal算法
    for(int i=0; i<m; i++)//依次加边法
    {
        if(Find(e[i].u)!=Find(e[i].v))//判断第i条边的起点和终点是否在同一个集合里
        {
            father[Find(e[i].u)]=Find(e[i].v);//如果不在一个集合就合并在一起
            tot+=e[i].w;//将第i条边加到最小生成树中
            k++;//边数增1
        }
        if(k==n-1)
        {
            break;//最小生成树的边数找够了,提前结束
        }
    }
    cout<<tot;
    return 0;
}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值