最小生成树(普里姆算法)

关于什么是Prim(普里姆算法)?

       在实际生活中,我们常常碰到类似这种一类问题:如果要在n个城市之间建立通信联络网,

则连通n个城市仅仅须要n-1条线路。这时。我们须要考虑这样一个问题。怎样在最节省经费前提

下建立这个通信网.换句话说,我们须要在这n个城市中找出一个包括全部城市的连通子图,使得

其全部边的经费之和最小. 这个问题能够转换为一个图论的问题:图中的每一个节点看成是一个城市,

节点之间的无向边表示修建该路的经费。即每条边都有其对应的权值,而我们的目标是挑选n-1条

边使全部节点保持连通。而且要使得经费之和最小.

       这里存在一个显而易见的事实是: 最优解中必定不存在循环(可通过反证法证明). 因此。最后找

出的包括全部城市的连通子图必定没有环路。

这样的连通且没有环路的连通图就简称为树。而在一个

连通图中删除全部的环路而形成的树叫做该图的生成树.对于城市建立通信连通网。须要找出的树由

于具有最小的经费之和。因此又被称为最小生成树(Minimum Cost Spanning Tree),简称MST.


 基本思路?

最小生成树相关概念:

       带权图:边赋以权值的图称为网或带权图,带权图的生成树也是带权的,生成树T各边的权值总和称为该树的权。

       最小生成树(MST):权值最小的生成树。

       生成树和最小生成树的应用:要连通n个城市需要n-1条边线路。可以把边上的权值解释为线路的造价。则最小生成树表示使其造价最小的生成树。

  因为生成树必须包括原图里面的全部节点。关键的问题就在于边的选择,怎么才干找出n-1条边,

使得全部节点连通。而且权重最小呢? 这里。我们先来看看MST有什么特点设有上图所看到的的最小生

成树T,假设删除边(u,v)T,则T将被分解成两个子树:T1和T2,因此。T1和T2各自是其所包括节点的最

小生成树。此处可用反证法证明:如果T1(也可如果为T2)不是其所包括节点的最小生成树。那么,势必

还存在的生成树T',那么,T'+w(u,v)+T2<T1+w(u,v)+T2。这与我们的如果T是最小生成树相矛盾,

故结论成立.

这就是最小生成树的最优子结构性质。在细想一下,MST也包括了重叠子问题的性质,那么似乎我们

能够用动态规划来解决.但假设用动态规划来解决MST,其时间复杂度是指数级别的。显然不是太可取,

我们须要找寻更好的方法.既然MST满足最优子结构性质,那么它是否满足贪婪选择属性呢?


为了更好地理解最小生成树请看例如以下的样例:

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

参考代码

#include<stdio.h>
#include<stdlib.h>
#define max 1000000000;
int a[1001][1001],d[1001],p[1001];
int main(){
	int i,j,k,m,n,min,ans,t;
	int x,y,z;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++){
		scanf("%d%d%d",&x,&y,&z);
		a[x][y]=z;
		a[y][x]=z;
	}
	for(i=1;i<=n;i++)
		d[i]=1000000000;
	d[1]=0;
	for(i=2;i<=n;i++){
		min=max;
		for(j=1;j<=n;j++)
			if(!p[j]&&min>d[j])
				min=d[j];
		t=j;
	}
	p[t]=j;
	for(j=1;j<=n;j++)
		if(a[t][j]=0&&d[j]>a[t][j]){
			d[j]=a[t][j];
			ans+=min;
		}
	printf("%d",ans);
	return 0;
}

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值