最小生成树-普林算法(Prim)/克鲁斯卡尔算法(Kruskal)

问题提出:

        一个公司计划建立一个通信网络来连接它的一个计算机中心。可以用租用的电话线连接这些中心的任何一对。应当妊娠瘙痒哪些连接,以便保证在任何两个计算机中心之间都有通路,且网络的总成本最小?可以用下较长所示的带权图为这个问题建模,其中顶点表示计算机中心,边表示可能租用的电话线,边上的权是边所表示的电话线的月租费。通过找出一棵生成树,使得这棵树的各边的权之和为最小,就可以解决这个问题。这样的生成树称为最小生成树。

最小生成树定义:
    在一个具有V个节点的连通无向图中,找到一个子图,该子图包含原图的所有节点和部分连接边,且不能形成回路,同时子图边的权值总和最小。
最小生成树的算法:
根据对安全边的不同规则,有两种算法可以生成最小生成树。即Kruskal算法和Prim算法。

1.普林算法(Prim)

        该算法所具有的一个性质是集合A中的边总是构成一棵树,而不是森林。这棵树从任意一个根节点开始,一直长大到覆盖V中所有的节点为止。算法每一步在链接集合A和A之外的节点的边,选择一条轻量级边加入到集合A中。
步骤:
设是带权值的连通图,A是上最小生成树中边的集合:
(1)初始令,(), A=NULL
(2)在所有,的边中,找一条权值最小的边
(3)将并入集合A,同时并入
(4)重复上述操作直至为止,则为的最小生成树
判断规则:在所有,的边中,找一条权值最小的边,连接该边,但不能形成回路;


举例:

该图为原始图
第一步:选取一个初始节点a为根节点,并找到权值为最小的边,即为ab;


第二步:在所有,的边中,找一条权值最小的边;即权值最小边为bc或者ah;这里选取bc


第三步:在所有,的边中,找一条权值最小的边;即选择ci;


第四步:在所有,的边中,找一条权值最小的边;即选择cf;


第五步:在所有,的边中,找一条权值最小的边;即选择fg;


第六步:在所有,的边中,找一条权值最小的边;即选择gh;


第七步:在所有,的边中,找一条权值最小的边;必须保证不能形成回路,即选择cd;




最后一步:在所有,的边中,找一条权值最小的边;必须保证不能形成回路,即选择de;由于树包含了所有节点,且满足,则在此终止,为的最小生成树。

         很简单的地说,就是建立一棵树T,和不在树中的顶点集合L,找出两者之间最短的距离的点,加入到树中,直到所有点加进去为止。
//d为图的邻近矩阵,p为所生成树的邻近矩阵,
//n为图中点的个数
void Prim(int **d,int **p,int n)
{
	int i,j,tmp,iT,iL;
	vector<int> T,L;//T是要生成的树,L为还没生成树的顶点
	for(i=0;i<n;i++)
		L.push_back(i);//给L赋初始
	while(L.size()){//当L为空时,即已经生成树完毕
		tmp=d[0][0];iT=iL=0;//以第一个点作为初始点
		for(i=0;i<T.size();i++){//找出树与非树顶点之间距离最小的点,并记录
			for(j=L.size()-1;j>=0;j--){
				if(tmp>=d[T[i]][L[j]]){
					tmp=d[T[i]][L[j]];
					iT=i;iL=j;
				}
			}
		}
		cout<<L[iL]<<" ";
		T.push_back(L[iL]);//将找到的点添加到树中
		p[T[iT]][L[iL]]=1;
		L.erase(L.begin()+iL);//且从剩余的点中删除
	}
	cout<<endl;
}


时间复杂度:
最小边、权的数据结构 时间复杂度(总计)
邻接矩阵、搜索O(V2)
二叉堆邻接表O((V + E) log(V)) = O(E log(V))
斐波那契堆邻接表O(E + V log(V))

2.克鲁斯卡尔算法(Kruskal)



3.网络资源

http://blog.csdn.net/chenhanzhun/article/details/39006205
http://blog.csdn.net/niushuai666/article/details/6689285
http://baike.baidu.com/view/247951.htm?fr=aladdin

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值