//海不辞水|

ccrui

园龄:2年2个月粉丝:2关注:4

2023-08-25 10:58阅读: 12评论: 0推荐: 0

最小生成树学习笔记


Prim算法

prim算法基本思想:基于点的解决方式

  1. 先随便选择一个点s作为起点,把其他所有点设为未添加节点,再设一dis数组,代表每个
    节点到最小生成树最近点的距离,易得一开始只有dis[s]=0,其他均为∞。
  2. 每轮找到dis值最小且未添加过的节点加入生成树中,且使用这个节点的邻边去更新它的邻
    点的dis值,如更新点为u,u->v有一条长度为x的边,则我们可以更新dis[v]为min(dis[v],x)。
  3. 重复执行操作②,直到所有点全部被添加。

伪代码

int prim(){
d[1]=0; mst=0;
for(each 除1以外的点v)d[v]=∞;
for(i=1~n){
找到未激活且d值最小的点u。
if(找不到u) return -1;
else mst+=d[u],u设为已激活;
for (each u的后继点v)
d[v]=min(d[v],G[u][v]);
}
return mst;
}

代码

struct point{
int d,s;
bool operator < (const point &a) const {
return s > a.s;
}
};
vector<point>v[50100];
int prim(){
int ans=0;
for(int i=1;i<=n;i++)dis[i]=1e9;
priority_queue<point>q;
dis[1]=0;
q.push(point{1,0});
while(!q.empty()&&c<n){
int u=q.top().d;
q.pop();
if(!b[u]){
c++;
b[u]=1;
for(int i=0;i<v[u].size();i++){
int d=v[u][i].d,s=v[u][i].s;
//cout<<d<<" "<<s<<' '<<dis[d]<<endl;
if(!b[d]&&dis[d]>s){
dis[d]=s;
q.push(point{d,dis[d]});
}
}
ans+=dis[u];
}
}
//cout<<c<<endl;
if(c==n)return ans;
else return -1;
}

Kruskal

考虑一种贪心的思想:从小到大加边

  1. 初始化。将所有边都按权值从小到大排序,将每个节点集合号都初始化为自身编号。

  2. 按排序后的顺序选择权值最小的边 u,v

  3. 如果节点 uv 属于两个不同的连通分支,则将边 (u,v) 加入边集 TE 中,并将两个连通分支合并。

  4. 如果选取的边数小于 n1 ,则转向步骤2,否则算法结束。

图解

image

结果:

image

伪代码

int kruskal(){
给边集按权值w排序。
mst=0
for(each 边集中的边(u,v,w)){
if(u和v不在一个集合中){
mst+=w;
将u和v连起来;
if(所有点在一个集合中)
return mst;
}
}
return -1;
}

代码

int fa[100001],n,k,m,ans,cnt;
struct edge{
int u,v,w;
}v[201000];
bool cmp(edge x,edge y){
return x.w<y.w;
}
int find(int x){
while(x!=fa[x])x=fa[x]=fa[fa[x]];
return x;
}
int kruskal(){
sort(v,v+m,cmp);
for(int i=0;i<=n;i++)fa[i]=i;
for(int i=0;i<m;i++){
int fu=find(v[i].u),fv=find(v[i].v);
if(fu==fv)continue;
ans+=v[i].w;
fa[fv]=fu;
cnt++;
if(cnt==n-1)return ans;
}
return -1;
}

复杂度

kruskal:O(mlogm)
prim:O(mlogn)

本文作者:ccrui

本文链接:https://www.cnblogs.com/ccr-note/p/MST.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   ccrui  阅读(12)  评论(0编辑  收藏  举报
评论
收藏
关注
推荐
深色
回顶
收起
点击右上角即可分享
微信分享提示