最小生成树(MST)

基本概念:


在无向图中,连通且不含圈的图称为 “” 。  

给定无向图G=(V,E), 连接G中所有点,且边集是E的子集的树称为G的  “生成树” 。

在G的所有生成树中,权值最小的那颗树称为  “最小生成树” 。 


构造MST的算法有很多,最常见的有两个 : Kruskal算法   和   Prime算法  。


Kruskal算法:(适用于稀疏图

原理: 

1. 将图中所给出的所有边按照从小到大的顺序排列,然后依次考察每条边(u,v)。

2. 

情况1. u和v在同一个连通分量中,那么加入(u,v)后会形成环,因此不能选择。

情况2. u和v在不同的连通分量中,那么就加入(u,v)。


相关算法: 并查集

并查集: 并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的元素所在的集合合并。


模板代码如下:

int u[MAX],v[MAX],w[MAX]; //u[i]表示一条边的起点,v[i]表示一条边的终点,w[i]表示改变的权值,i表示该边的编号。

int cmp(const int i,const int j)   //间接排序函数
{
    return w[i]<w[j];
}

int find(int x)    //并查集的find
{
    return p[x]==x?x:find(p[x]);
}

int Kruskal()
{
    int ans=0;
    for(int i=0;i<n;i++) p[i]=i;    //初始化并查集
    for(int i=0;i<m;i++) r[i]=i;    //初始化边序号
    sort(r,r+m,cmp);                //给边排序
    for(int i=0;i<m;i++)
    {
        int e=r[i];
        int x=find(u[e]);
        int y=find(v[e]);    //找出当前边两个端点所在集合编号
        if(x!=y)              // 如果在不同集合,就合并   
        {
            ans+=w[e]; p[x]=y;    
        }
    }
    return ans;
}



Prime算法: (适合稠密图

prime算法和边数无关,只和顶点数量有关。

基本原理:

1. 将一个图的顶点分为两部分,一部分是最小生成树中的结点(A集合),另一部分是未处理的结点(B集合)。

2. 首先选择一个顶点放入集合A中,然后遍历集合B中的所有顶点,找出与A中顶点关联的所有边中权值最小的一条边(顶点为v),将v从B集合中删除并加入A集合。

3.递归重复步骤2,直到B集合中的顶点为空,结束此过程。


模板代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
#define INF 0xffffff
#define MAXN 110
int map[MAXN][MAXN], lowcost[MAXN];
bool visit[MAXN];
int nodenum, sum;

void prim()
{
	int temp, k;
	sum = 0;
	memset(visit, false, sizeof(visit)); //初始化visit
	visit[1] = true;
	for(int i = 1; i <= nodenum; ++i) //初始化lowcost[i]
		lowcost[i] = map[1][i];
	for(int i = 1; i < nodenum; ++i)//找生成树集合点集相连最小权值的边
	{
		temp = INF;
		for(int j = 1; j <= nodenum; ++j)
			if(!visit[j] && temp > lowcost[j])
				temp = lowcost[k = j];
		if(temp == INF) break;
		visit[k] = true;                  //加入最小生成树集合
		sum += temp;                      //记录权值之和
		for(int j = 1; j <= nodenum; ++j) //更新lowcost数组
			if(!visit[j] && lowcost[j] > map[k][j])
				lowcost[j] = map[k][j];
	}
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值