【模板】MST最小生成树(Prim算法、Krustra算法)

MST最小生成树问题

给一张n个点的图,从中选 n-1条边,使得所选边权和最小的情况下生成一个树。
解法核心:贪心

法一:Prim算法

1、核心思路: 点集拓展

2、核心操作:贪心(优先队列实现) + 判环(集合/标记 实现)

3、算法流程:

step1. 随机选取一个点不在集合内的点,并将该点连接的所有边加入优先队列,
step2. 选取优先队列的top(即集合当前所连接所有边中的最短边),将该边作为树的其中一个边,
step3. 将所连向的to_pos加入集合,如果该点已经在集合,则换下一条边,进行前述操作。
step4. 重复上述操作,直到所有点全部加入集合
注:推荐使用邻接矩阵。

4、复杂度分析:

O( N + logM) ⇒ 适用于密集图(边较多时)

5、 代码模板:

struct ss{//邻接表存图
	int to,nex,va;
	bool operator >const (ss b){return va<b.va;}
}edge[N];int head[N],ecnt;
priority_queue<ss> Q;
int prim(){
	vis[1]=true;int count=1,ans=0;//把第一个点放进去(也可以是任意一个)
	for(int i=head[1];i;i=edge[i].nex) Q.push(edge[i]);
	while(count<n && !Q.empty()){
		int to=Q.top().to;Q.pop();
		if(vis[to]) continue;
		count++;ans+=Q.top().va; vis[to]=true;//记录答案+集合标记
		for(int i=head[to];i;i=edge[i].nex) //放入边
		if(!vis[edge[i].to]) Q.push(edge[i]);//排序时间挺长的,能不入队就不入队
	}if(count<n) return -1;//图不连通,报错
	return ans;
}

法二:Krustra算法

1、核心思路: 选边法

2、核心操作:贪心(一次排序实现) + 判环(并查集实现)

3、算法流程:

step1. 将所有边排序
step2. 每次都选取最短的边,将该边作为树的边,
如果该边所连向的两个点 已经在同一并查集,则弃之不用
否则该边合法,选用该边,更新并查集
step4. 重复前述操作,直至n-1条边被选用,或直至所有边被遍历一遍

4、复杂度分析:

算法复杂度: O(m logm) ⇒ 适用于稀疏图(边较少时)

5、 代码模板:

struct ss{//邻接表存图
	int x,y,va;
}edge[N];int f[N];
bool cmp(ss a,ss b){return a.va<b.va;}
int fa(int x){//路径压缩并查集
	if(f[x]==x) return x;
	else return f[x]=fa(f[x]);
}
int krustra(){
	sort(edge+1,edge+m+1,cmp);int ans=0,count=0;
	for(i=1;i<=m;i++){
		int x=edge[i].x,y=edge[i].y;
		if(fa(x)==fa(y)) continue;//已经连通
		ans+=edge[i].va;//更新答案
		f[x]=fa(y);//更新连接
		count++;if(count==n-1) break;//剪枝
	}return ans;
}

注: prim算法如果要做非连通图的最小生成森林树,则需外面加一个循环,将所有点都视为初始放入节点。


ps.补一些基础模板,以便自己使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GoesM

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值