前言
最小生成树是什么?
一张连通图G的一个极大无环子图就是连通图G的生成树,通俗来讲就是从图中找出一棵树包含全部的点,一个图不只一棵生成树,其中权值最小的那若干棵树就是最小> 生成树
如何构建最小生成树
kruskal法
思路:贪心,每次都看最小的边合不合适。
- 从图中取出权值最小的边
- 判断边是否构成回路
- 构成回路,舍弃
- 不构成回路,成为树的一条边
- 重复1,2步骤,直至树中有n-1条边
代码实现
并查集
用于判断某条边是否与已有的边集构成回路,对某条边a->b,若a,b都是树中的点则边ab会与树构成回路
//并查集
const int M=1e5+10;
int fa[M];
//路径压缩
int find(int a){
//return fa[a]<0?a:find(fa[a]);
int r;
for(r=a;fa[r]>0;r=fa[r]);
while(a!=r){
int tmp=fa[a];
fa[a]=r;
a=tmp;
}
return a;
}
//加权合并
void merge(int a,int b){
int ia=find(a),ib=find(b);
if(ia==ib){
return;
}
//
if(ia<=ib){
fa[ia]+=fa[ib];
fa[ib]=ia;
}else{
fa[ib]+=fa[ia];
fa[ia]=ib;
}
}
图储存结构
const int N=1e5+10;
struct Edge{
int start,end;
int w;
}graph[N];
kruskal算法
//重载小于号使用优先队列构建小顶堆,选取权值最小的边
bool operator<(const Edge &a,const Edge &b){
return a.w>b.w;
}
void kruskal(){
memset(fa,-1,sizeof(fa));
//构建小顶堆
priority_queue<Edge> pq;
cin>>n>>m;
Edge tmp;
for(int i=0;i<m;i++){
cin>>tmp.start>>tmp.end>>tmp.w;
pq.push(tmp);
}
int cnt=1;
while(!pq.empty()&&cnt<n){
tmp=pq.top(),pq.pop();
if(find(tmp.start)==find(tmp.end)){
continue;
}
merge(tmp.start,tmp.end);
cout<<tmp.start<<" "<<tmp.end<<endl;
cnt++;
}
}