最小生成树

最小生成树的概念

最小生成树(Minimum Spanning Tree,简称MST)是图论中的一个概念,指的是在一个加权无向图中,通过遍历图的所有顶点,选择总权值最小的边集,构成一棵包含所有顶点的树,这棵树被称为最小生成树。最小生成树的特点是树中不存在任何环,且树的总权值(即所有边的权值之和)最小。

最小生成树的算法

最小生成树常用的算法有Prim算法和Kruskal算法两种。

Prim算法

Prim算法的基本思想是从图的某个顶点开始,每次选择与已有生成树顶点相连的权值最小的边,将其加入到生成树中,直到所有顶点都被访问过。这个过程保证了每次选择的边都会最小化树的总权值。

Kruskal算法

Kruskal算法则是通过对所有边进行排序,然后从小到大选择边,每次选择时确保不会产生环,直到树中有 条边,其中 是图的顶点数量。这种方法同样保证了树的总权值最小。n-1n

最小生成树的C++实现

在C++中实现最小生成树,通常需要使用一些基础的数据结构,如优先队列(用于Prim算法)或并查集(用于Kruskal算法)。以下是一些关键的C++代码片段,展示了如何在C++中实现最小生成树。

Prim算法的C++实现
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> p; 
int prim(vector<vector<p> >&graph){
	int n=graph.size();//图的点数 
	vector<bool> visited(n,0);//记录点是否被访问过 
	priority_queue<p,vector<p>,greater<p> > pq;//优先队列,用于权重最小的边 
	int minCost=0;//最小生成树 
	//将第一个点加入最小生成树 
	pq.push({0,0});//初始化权重为0 
	while(!pq.empty()){
		p t=pq.top();
		pq.pop();
		int u=t.first;//当前点 
		int w=t.second;//边的权重 
		if(visited[u]) continue;//如果点已经被访问过,跳过 
		minCost+=w;//将边的权重加入总权重 
		visited[u]=1;//标记点为已访问 
		//将与当前点相连且为访问过的边加入优先队列 
		for(int i=0;i<graph[u].size();i++){
			int v=graph[u][i].first;//相邻的点 
			int weight=graph[u][i].second;//边的权重 
			if(!visited[v]) pq.push({weight,v});
		}
	}
	return minCost;
}
int main(){
	int n,m;//n为顶点数,m为边数 
	cin>>n>>m;
	//初始化图的邻接表表示 
	vector<vector<p> > graph;//图的邻接表 
	for(int i=0;i<m;i++){
		int u,v,w;//边的起点、终点、权重 
		cin>>u>>v>>w;
		graph[u].push_back({v,w});
		graph[v].push_back({u,w});//无向边需要双向连接 
	}
	int minCost=prim(graph);//计算最小生成树的总权重 
	cout<<"Mininum Cost of Spanning Tree: "<<minCost;
	return 0;
}
Kruskal算法的C++实现
#include<bits/stdc++.h>
using namespace std;

//边的结构体——template-自动匹配数据类型 
template<typename T> 
struct Edge{
	int u,v;
	T weight;
	Edge(int u,int v,T weight) : u(u), v(v), weight(weight) {}
	//重载小运算符,用于排序 
	bool operator<(const Edge<T>& other) const {
		return weight<other.weight;
	}
};

//并查集的实现 
class DisjointSet{
	private:
		vector<int> parent;
	public:
		DisjointSet(int n):parent(n,-1){}
		int find(int x){
			if(parent[x]==-1) return x;
			return parent[x]=find(parent[x]);
		}
		void unite(int x,int y){
			int xSet=find(x);
			int ySet=find(y);
			if(xSet!=ySet){
				parent[xSet]=ySet;
			}
		}
};

//kruskal算法 
template<typename T>
T kruskal(vector<Edge<T>>& edges,int n){
	//按照权重对方进行排序 
	sort(edges.begin(),edges.end());
	DisjointSet ds(n);//初始化并查集 
	T minCost=0;//最小生成树的总权重 
	for(int i=0;i<edges.size();i++){
		Edge<T>& edge=edges[i];
		if(ds.find(edge.u)!=ds.find(edge.v)){
			minCost+=edge.weight;//将边的权重加入总权重 
			ds.unite(edge.u,edge.v);//将边的连个定点合并到一个集合中 
		}
	}
	return minCost;
}

int main(){
	int n,m;//n为顶点数,m为边数 
	cin>>n>>m;
	vector<Edge<int> > edges;//存储边的数组 
	for(int i=0;i<m;i++){
		int u,v,w;
		cin>>u>>v>>w;
		edges.emplace_back(u,v,w);
	}
	int minCost=kruskal(edges,n);//计算最小生成树的请权重 
	cout<<"Mininum Cost of Spanning Tree:"<<minCost<<endl;
	return 0;
}

注意事项

在实现最小生成树时,需要注意数据结构的选用以及算法的细节实现,以确保算法的正确性和效率。此外,对于大型图,可能需要使用更高效的数据结构(如斐波那契堆)来优化算法性能。在实际应用中,选择合适的算法和数据结构对于解决问题至关重要。

  • 10
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值