最小生成树笔记--《算法导论》

1、何为最小生成树(Minimum Spanning Tree)问题?
对于一个有权的联通无向图G=(V,E,ω),我们希望找到一个无环子集T⊆E,将所有节点连接起来并使总权值最低。
由于T是无环的,并且是联通的,所以T必然是一棵树,且是由G生成的生成树。我们将在G中求取这样一个T的问题叫做最小生成树问题。
求取该问题有两种算法:Kruskal算法和Prim算法,这两种算法都是基于贪心算法。

图像来源于百度文库


2、最小生成树的证明
①核心思想:每个时刻生长最小生成树的一条边。且满足下列规则:令A为某颗最小生成树的一个子集,每一步中在G中选择一条边(u,v)加入A中,使A∪{(u,v)}仍然为某颗最小生成树的子集。(这样的边称为A的安全边

②证明所需前置概念:
无向图G=(V,E)的一个切割(S,V-S)是集合V的一个划分。如果一条边(u,v)∈E的一个端点在S、另一个在V-S上,则称该边横跨切割(S,V-S)。对于一个集合A⊆E,如果A中不存在横跨该切割的边,则称该切割尊重集合A。在横跨一个切割的所有边中,权重最小的边称为轻量级边

③用来辨认安全边的相关定理。
定理一:设G=(V,E)是一个在边E上定义了实数值权重函数ω的连通无向图。设集合A为E的一个子集,且A包括在G的某颗最小生成树中,设(S,V-S)是G中尊重集合A的任意一个切割,又设(u,v)为横跨该切割的一条轻量级边,则边(u,v)对于集合A来说是安全的。


3、Kruskal算法和Prim算法
这两种算法都是采用一条具体的规则来确定2中的安全边。在Kruskal算法中,集合A为一个森林,其结点为给定图的结点,每次加入到A中的安全边永远是权重最小的连接两个不同分量的边。而Prim算法中,集合A为一颗树,每次加入A中的安全边永远是连接A和A之外某个结点的边中权重最小的边 。

Prim算法(基于邻接矩阵构造的图):

void MiniSpanTree_Prim(MGraph G)
{
   int min,i,j,k;
   int adjvex[MAXVEX];//store the relevant vex 
   int lowcost[MAXVEX];//store the relevant cost 
   lowcost[0]=0;
   adjvex[0]=0;
   for(i=1;i<G.numVertexes;i++)
   {
      lowcost[i]=G.arc[0][i];
      adjvex[i]=0;
   }
   for(i=1;i<G.numVertexes;i++)
   {
      min=INFINITY;
      j=1;k=0;
      while(j<G.numVertexes)
      {
         if(lowcost[j]!=0&&lowcost[j]<min)
         {
            min=lowcost[j];
            k=j;
         }
         j++;
      }
      printf("(%d,%d)",adjvex[k],k);
      lowcost[k]=0;
      for(j=1;j<G.numVertexes;j++)
      {
         if(lowcost[j]!=0&&G.arc[k][j]<lowcost[j])
         { 
            lowcost[j]=G.arc[k][j];
            adjvex[j]=k;
         }
      }   
   }
}

Kruskal算法(基于边集数组构造的图):

typedef struct
{
   int begin;
   int end;
   int weight;
}Edge;

void MiniSpanTree_Kruskal(MGraph G)
{
   int i,n,m;
   Edge edges[MAXEDGE];
   int parent[MAXEDGE];//to check if they cause a circuit
   for(i=0;i<G.numVertexes;i++)
      parent[i]=0;
   for(i=0;i<G.numEdges;i++)
   {
      n=Find(parent,edges[i].begin);
      m=Find(parent,edges[i].end);
      if(n!=m)
      {
         parent[n]=m;
         printf("(%d,%d) %d",edges[i].begin,edges[i].end,edges[i].weight);
      }

   }
}

int Find(int *parent,int f)
{
   while(parent[f]>0)
      f=parent[f];
   return f;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值