概念
生成树
信息学里的树???
图论中一个V个点的图,取其中V-1条边,将他们连接起来,就是生成树。
最小生成树
生成树中边权总和最小的生成树,就是最小生成树。
图示
特点
1.环属性
一颗生成树上任意加一条边,必构成环。
再去掉环上最大权边,就得到了一颗可能更好的生成树。
2.剪切属性
生成树可以分成不相交两个集合(可以看作两颗子生成树),两颗子生成树之间有交叉边。最小交叉边一定要在最小生成树上。
3.其他
prim
算法
利用剪切属性,将点分为两个集合A,B。初始时A集合只有源点。
枚举每个交叉边,取最小边【i,j】,将边终点j加入集合A,用他更新到达B集合每条最短交叉边。
图示
代码
void prim(int s)
{
memset(dis,10,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[s]=0;
vis[s]=1;
for(int i=linkk[s];i;i=a[i].next)
dis[a[i].y]=a[i].v;//初始化
for(int k=1;k<n;k++)
{
int minn=dis[0],c=0;
for(int i=1;i<=n;i++)
if (!vis[i]&&dis[i]<minn)
{
minn=dis[i];
c=j;
}
vis[c]=1;//加入集合A
ans+=minn;
for(int i=linkk[c];i;i=a[i].next)
{
int tn=a[i].y;
if (!vis[tn]&&dis[tn]>a[i].v)
dis[tn]=a[i].v;
}//更新最短路。
}
}
kruscal
算法
由于要用到并查集,所以介绍下并查集http://blog.csdn.net/OIer00LCJ/article/details/78919112
kruscal是将所有边进行排序,因为最小边原则,将最小交叉边【i,j】入队,将【i,j】进行并集操作,使他们成为一个集合,也就是连了边;
进行n-1次合并后,就得到了一颗最小生成树。
图示
代码
int fa[maxn]={};
void init()//初始化
{
for(int i=1;i<=n;i++)
fa[i]=i;
}
int getfather(int x)//找父结点+路径压缩
{
return (fa[x]==x) ? x:fa[x]=getfather(fa[x]);
}
void hebing(int x,int y)//合并
{
int fx=getfather(x),fy=getfather(y);
fa[fx]=fy;
}
//并查集基本操作
void kruscal()
{
int c=0;//计数器
int ans=0;
sort(a+1,a+t+1);
for(int i=1;i<=t;i++)
{
int x1=getfather(a[i].x);
int y1=getfather(a[i].y);
if (x1!=y1)
{
ans+=a[i].v;
hebing(x1,y1);
if(++c==n-1)
break;
}
}
}
总结
prim算法
1.时间复杂度O(n^2);
2.可用堆优化O((E+V)*logV)
krusacl算法
1.时间复杂度O(E*logE+N*A*V)
2.适用于稀疏图。