最小生成树详解

一、概念

1、

最小生成树是一副连通加权无向图中一棵权值最小的生成树

如下图黑线表示的是一个最小生成树

最小生成树详解_第1张图片

2、

一个连通图可能有多个生成树。当图中的边具有权值时,总会有一个生成树的边的权值之和小于或者等于其它生成树的边的权值之和。广义上而言,对于非连通无向图来说,它的每一连通分量同样有最小生成树,它们的并被称为最小生成森林

 

二、相关性质

1、个数多个

最小生成树在一些情况下可能会有多个

例如,当图的每一条边的权值都相同时,该图的所有生成树都是最小生成树。

例如下图

最小生成树详解_第2张图片

 

如果图的每一条边的权值都互不相同,那么最小生成树将只有一个,这一定理同样适用于最小生成森林。

2、边的权值之和最低的子图

如果图的边的权值都为正数,那么最小生成树就是该图的所有包含所有顶点的子图中权值最低的子图。

3、环定理

对于连通图中的任意一个环:如果中有边 的权值大于该环中任意一个其它的边的权值,那么这个边不会是最小生成树中的边

证明:
假设 属于最小生成树 ,那么将 删去将会使得 变为两个树。因为环 必然还存在另一横切边f可以连接两个子树形成生成树 ,且由于 < ,生成树 权值更小,与 是最小生成树矛盾。

4、最小权值边

如果图的具有最小权值的边只有一条,那么这条边包含在任意一个最小生成树中。

 

三、Prim(普利姆算法)

1、思想

 1.从图中选取一个节点作为起始节点(也是树的根节点),标记为已达;初始化所有未达节点到树的距离为到根节点的距离;

 2. 从剩余未达节点中选取到树距离最短的节点i,标记为已达;更新未达节点到树的距离(如果节点到节点i的距离小于现距离,则更新);

 3. 重复步骤2直到所有n个节点均为已达。

 

图例 说明 不可选 可选 已选
最小生成树详解_第3张图片 此为原始的加权连通图。每条边一侧的数字代表其权值。 - - -
最小生成树详解_第4张图片 顶点D被任意选为起始点。顶点ABEF通过单条边与D相连。A是距离D最近的顶点,因此将A及对应边AD以高亮表示。 C, G A, B, E, F D
最小生成树详解_第5张图片 下一个顶点为距离DA最近的顶点。BD为9,距A为7,ED为15,FD为6。因此,FDA最近,因此将顶点F与相应边DF以高亮表示。 C, G B, E, F A, D
Prim Algorithm 3.svg 算法继续重复上面的步骤。距离A为7的顶点B被高亮表示。 C B, E, G A, D, F
最小生成树详解_第6张图片 在当前情况下,可以在CEG间进行选择。CB为8,EB为7,GF为11。E最近,因此将顶点E与相应边BE高亮表示。 C, E, G A, D, F, B
最小生成树详解_第7张图片 这里,可供选择的顶点只有CGCE为5,GE为9,故选取C,并与边EC一同高亮表示。 C, G A, D, F, B, E
最小生成树详解_第8张图片 顶点G是唯一剩下的顶点,它距F为11,距E为9,E最近,故高亮表示G及相应边EG G A, D, F, B, E, C
现在,所有顶点均已被选取,图中绿色部分即为连通图的最小生成树。在此例中,最小生成树的权值之和为39。

A, D, F, B, E, C, G

 

2、CODE:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
typedef long long LL;
using namespace std;
#define memset(a,n) memset(a,n,sizeof(a))
#define INF 0x3f3f3f3f

int dis[105];
int vis[105];
int mapp[105][105];
int n,m;

void Prim()
{
    int sum=0;
    for(int i=1;i<=m;i++)
        dis[i]=mapp[1][i];

    vis[1]=1;
    dis[1]=0;

    int minn=INF,pos=INF;
    for(int i=1;imapp[pos][j])
                dis[j]=mapp[pos][j];

    }
  
  printf("%d\n",sum);
}

int main()
{
    int be,en,v;
    while(scanf("%d %d",&n,&m)&&n!=0) // m 为顶点,n 为边
    {
        memset(vis,0);
        memset(dis,INF);
        memset(mapp,INF);

        for(int i=0;iv) // 防止重边,只保留这两个顶点间更小的一个边
                mapp[be][en]=mapp[en][be]=v;
        }

        Prim();
    }
}

 

四、Kurskal(克鲁斯卡尔算法)

1、思想

 

  1. 新建图G,G中拥有原图中相同的节点,但没有边
  2. 将原图中所有的边按权值从小到大排序
  3. 从权值最小的边开始,这条边与图中已有的边不形成环,则加入该条边
  4. 重复3,直至图G中所有的节点都在同一个连通分量中

2、判断成不成环,需要用到 并查集

3、CODE:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
typedef long long LL;
using namespace std;
#define memset(a,n) memset(a,n,sizeof(a))
#define INF 0x3f3f3f3f

int pre[110];
int find(int x)
{
    if(x!=pre[x]){
        pre[x]=find(pre[x]);
    }
    return pre[x];
}
void Merge(int a,int b)
{
    int root1=find(a);
    int root2=find(b);
    if(root1!=root2){
        pre[root1]=root2;
    }
}

int main()
{
    int n,m,a,b;
    while(scanf("%d",&n)&&n!=0){
        scanf("%d",&m);

        for(int i=1;i<=n;i++)
            pre[i]=i;

        for(int i=0;i

二、与最短路区别:

最小生成树能够保证整个拓扑图的所有路径之和最小,但不能保证任意两点之间是最短路径。
最短路径是从一点出发,到达目的地的路径最小。

 

三、例题详解

有关例题

你可能感兴趣的:(ACM,----,知识点,ACM,----,图论)