最小生成树 prim和kruskal算法

           生成最小的生成树的过程其实就是寻找安全边的过程,prim和kruskal从图的两个基本构成出发,即边和点的两个不同的角度,来寻找安全边。

安全边:

假设集合a是最小生成树的一个子集,我们要做的就是每次寻找一条边(u,v)。将其加入到集合a中,使得集合a与边(u,v)的并集仍然是最小生成树的子集,则称这条边是安全边。

定理:

首先设图g=(v,e)是一个无向联通图,设集合a为e的一个最小生成树,设(s,v-s)是尊重集合a的一个切割,又设边(u,v)是横跨切割的轻量级边,则边(u,v)对于集合a来说是安全的。

   1.prim(点)

       算法从任意的点开始,每次在集合a和a之外的节点中的所有边汇总选择一条轻量级的边,加入到a中,有定理可知,边a总是安全的。故当算法结束的时候,最小生成树是正确的,且本策略属于贪心的方法,但是是正确的。

      简单的prim算法就是基本的循环就能跑出来结果,下附上简单的代码:

   

  1. while(true)  
  2.     {  
  3.         if(m==n)  //生成树完成后跳出循环
  4.             break;  
  5.   
  6.         min_w=inf;  //每次寻找续最小的边,记得是在循环内部每次进行初始化
  7.         for(int i=2;i<=n;i++)  
  8.         {  
  9.             if(!u[i] && low_dis[i]>dist[s][i])  
  10.                 low_dis[i] = dist[s][i];  //更新树到每个点的距离
  11.             if(!u[i] && min_w>low_dis[i])  
  12.             {  
  13.                 min_w = low_dis[i];  //寻找最小的距离
  14.                 point=i;  
  15.                   
  16.             }  
  17.         }  
  18.       
  19.         s=point; //每次更新源点
  20.         u[s]=true;  //吧选过的点标记
  21.         m++;//次数加一 

  

2.kruskal(边)

在所有连接不同树的边里面,每次选取一条最小的边(u,v),由于边一定是链接集合a与其他树的轻量级边,利用贪心的做法,其实和prim算法一样,利用了定理:

附上简单的代码:

   使用了较为渐大的数据结构:并茶集:

struct node
{
int x;int y;
int wei;
}edge[maxn*maxn/2];
bool cmp(node a,node b)
{
return a.wei<b.wei;
}

int findf(int x)
{
if(x!=father[x])
father[x]=findf(father[x]);
return father[x];
}
void ini(int x)
{
father[x]=x;
}
void un(int x,int y,int w)
{
if(x==y)
return ;
father[y]=x;
if(w>cun)
cun=w;

}
void solve(int len)
{
for(int i=1;i<=len;i++)
un(findf(edge[i].x),findf(edge[i].y),edge[i].wei);

}

 

  

 

转载于:https://www.cnblogs.com/keephungry/p/3302570.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值