您的位置:首页 > 其它

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

2014-12-04 14:17 1341 查看

问题提出:

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

最小生成树定义:

在一个具有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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: