最小生成树
0.2
目录
基本概念
最小生成树是一棵由无向连通图转成的树,连接每个节点的值总和最短.由此可以看出其采用的算法:贪心和排序.
Prime算法
邻接矩阵复杂度O(v^2),邻接表O(e*log2v).e-边,v-点.
基本思路
- 选择一个点作为根节点
- 枚举每一条与该点连接的边,将其存入数组
- 如果枚举到的比存储的到达某个点的边更短,更新.
- 从数组中选出一条最短边拓展,同时保留其余边
- 最短总值加上该边权值
- 重复2-5直到没有边或没有点为止
实现代码
void prime()
{
bool v[n+1]={0};
int d[n+1];//表示从到达点的最短边长度
meeset(d,1,sizeof(d));
q.push(1);
d[1]=0;
while(!q.empty())
{
int x=q.front(),mi=999999,co=0;
q.pop();
v[x]=true;
for(int i=1;i<=n;i++)//找出最短边
if(mi>d[t])
{
mi=d[t];
co=t;
}
if(!co) return;
ans+=mi;
q.push(co);
for(int i=1;i<=a[co][0];i++)
//a[co][i]记录与co连接的点,a[i][0]是数量
if(!v[a[co][i]]&&c[co][a[co][i]]<d[i])
d[i]=c[co][a[co][i]];
}
}
优化方案
显而易见,mi的期望值始终是d[]中最小值.则引入一个二叉堆优化,每次取头即可.
复杂度O(e*logv).
struct R
{
int co,w;
}
priority_queue<R>q;
void prime()
{
bool v[n+1]={0};
R t;
t.w=0;
t.co=1;
q.push(t);
while(!q.empty())
{
R x=q.top();
q.pop();
v[x.co]=true;
if(!x.co) return;
ans+=x.w;
for(int i=1;i<=a[co][0];i++)
if(!v[a[x.co][i]])
{
t.w=c[x.co][a[x.co][0]];
t.co=a[x.co][i];
q.push(t);
}
}
}
Kruscal算法
- Kruscal算法用到了贪心思想,每次加入一条最短边,用并查集维护树的结构
- Kruscal算法适用于稀疏图,复杂度O(e*loge).
代码实现
#include <algorithm>
//基本都是结合,只定义函数
int find(int x);
bool he(int x,int y)//判断能否合并
void Kruscal()
{
int e=0;
sort();
for(int i=1;i<=ro&&e<=n-1;i++)
if(he(a[i].co,a[i+1].co))
{
ans+=a[i].c;
e++;
}
if(e<n-1)//图不连通
ans=-1;
}