Prim算法的实现过程?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Prim算法的实现过程?相关的知识,希望对你有一定的参考价值。
精髓部分
G=(V,E)①初始化:读入的数据用邻接矩阵x存储,一个一维布尔型数组chosen,记录第i个节点是否已选,初始值除1外全部设为false,记录权值的变量cost赋值为0;
以下②到④循环执行v-1次(每次生成一条边,运行(点的个数减1)次后,生成一棵最小生成树):
②临时变量p赋值为无限大,用于记录当前最小值;
③二重循环(外循环i,内循环j)扫描邻接矩阵:如果chosen[i]=true(也就是说第i个点已选),那么扫描x[i],如果not(chosen[j])(也就是说第j个点未选),那么如果x[i,j]<p,那么p赋值为x[i,j],临时变量q赋值为j;
④把cost赋值为cost+o,把chosen[q]赋值为true(也就是说第j个点已选);
⑤输出cost。
一、以上给出具体的运行过程。这个算法的策略就是贪心,和dijkstra差不多,每次都选择未选的边中权值最小的那一条,直到生成最小生成树。用chosen的目的就是保证生成过程中没有环出现,也就是说保证选择的边不会通向一个已经包含在生成树中的点。
二、这个只输出最小生成树的每条边权值之和,如果要输出整棵最小生成树,加一个[1..n,1..2]的数组,在第④步的时候把每次选的边记录下来就可以了。
三、用小顶堆在第③步优化一下的话就不用每次都扫描那么多边了,只不过建堆维护堆代码写起来很麻烦。
四、prim适合用于比较稠密的网,点数和边数差不多的时候效率很恶心,一般都用kruskal。 参考技术A 贪心过程.
首先,把图中的点分成两种,已连通和未连通的,我把它们分别称为"黑"和"白"点.
一开始时,图中全是白点,没有黑点.算法的第一步,随机选出一个白点,染成黑色.
然后开始一个重复的过程:
从当前图的边中寻找这样的一些边:它的其中一个端点是黑点,而另一个端点是一个白点. 我们可以把这类边称为"可扩展边". 然后算法需要从所有的可扩展边之中选出权值最小的一条.把这条可扩展边加入生成树之中,且把这条边的白色端点染成黑色.
重复这个过程,直到全部的节点都为黑色.
算法可以优化的地方是,在选择权值最小的可行边时可以使用堆. 参考技术B Prim算法,是指图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值之和亦为最小。该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克发现,并在1957年由美国计算机科学家罗伯特·普里姆独立发现,1959年,艾兹格·迪科斯彻再次发现了该算法。因此,在某些场合,普里姆算法又被称为DJP算法、亚尔尼克算法或普里姆亚尔尼克算法。
Prim算法
适用范围
最小生成树问题
思路
核心思想:贪心.对于一幅连通图,首先,先假设有一个只包含顶点v的数T,然后贪心选取T和其他点之间的最小权值的边,然后把它加入T,不断进行这个操作直到所有点的都在T里,这时T就是最小生成树.prim算法和dijkstra算法很相似,实现的时候也差不多,基础算法像dijkstra一样可优化,用优先队列来优化选最小权值的边的过程.优化后复杂度(ElogV) E边V点
代码
1 typedef pair<int,int> P;//first是边权值,second是点 2 struct edge{int to,cost;}; 3 vector<edge> es[MAX]; 4 bool used[MAX]; //点编号从1开始 5 6 int prim(void) 7 { 8 priority_queue<P,vector<P>,greater<P> > que; 9 int ans=0; 10 used[1]=true; 11 for(int i=0;i<es[1].size();i++) 12 que.push(P(es[1][i].cost,es[1][i].to)); 13 while(que.size()) 14 { 15 P p=que.top();que.pop(); 16 int x=p.second; 17 if(used[x]) continue; 18 used[x]=true; 19 ans+=p.first; 20 for(int i=0;i<es[x].size();i++) 21 if(!used[es[x][i].to]) que.push(P(es[x][i].cost,es[x][i].to)); 22 } 23 return ans; 24 }
以上是关于Prim算法的实现过程?的主要内容,如果未能解决你的问题,请参考以下文章