最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解
Posted JiYH
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解相关的知识,希望对你有一定的参考价值。
最小生成树
Prim(普雷姆)算法
以某一个顶点开始构建生成树,每次将代价最小的新顶点纳入生成树,直到所有顶点都纳入位置。设有如下图:
从P点开始构建生成树,选择其他顶点也可
首先与P相连最小的代价(边)是学校,代价为1,将其并入:
此时与生成树相连的边有5,6,5,4,6,4,最小的代价时连渔村或者矿场,我们这里选择连矿场,选渔村的话生成的最小生成树代价不变,所以同一个图可以有多个最小生成树此时最小树生成树如图:
再选择代价最小的顶点并入生成树,依此类推,最小生成树:
Kruskal (克鲁斯卡尔)算法
每次选择一条权值最小的边,使这条边的两头联通(原本已经联通的就不选),直到所有结点都联通。
还是上面的例子:
首先选出权值最小的一条边,显然是1,使连通。
再选出权值最小的边,<渔村,矿场>权值为2,使连通
再次选择权值最小的边,显然为<农场,电站>3
再次重复上述步骤发现,权值最小的边有两个,<P城,矿场>4,<P城,渔村>4,而P城与这两个边均为连通,我们随便选一条,假设选择<P城,矿场>4:
此时P城,矿场,渔村,是连通的,不能再选择<P城,渔村>4这条边了,同理不能选择<学校,矿场>5,而是选择<农场,P城>5边。最小生成树与普雷姆算法一致。
对比
最短路径问题
单源最短路径:即求图中某一顶点到其他各顶点的最短路径。
使用广度优先搜索(BFS)可以实现对无权图的单源最短路径的求解。
但对于有权图来说BFS不在适用,可考虑迪杰斯特拉算法求单源路径长度,求各顶点的最短路径考虑弗洛伊德算法。
Dijkstra(迪杰斯特拉)算法
设有以下图,求V0的单源最短路径:
初始化,发现从V0可以直接到V1, V4。dist[1]表示此刻能找到的从V0到V1的最短路径,V2,V3因为不存在直接和V1相连的边,所以dist为无穷大。path表示路径结点前驱,我们此时最短路径10,5都是由V0直接指向的,所以V1,V4的前驱自然为0(V0)。
第一轮循环:找到还没确定最短路径(即final值为false,dist最小的顶点),顶点V4,将其设置为true,
为什么要将V4设为true?已经找到了V0到V4的最短路径了吗?是的,因为我们选择的是与V0相邻的,边权值最小的顶点,如果<V0, V4>路径通过V1中转最小,那么第一轮循环选择的顶点应该是V1而不是V4.
检查所有邻接V4的顶点,若其值为false,更新它的dist和path数组信息。如何更新?以V1为例子,检查到V1的路径长度通过V4中转权值会不会更小。V0通过V4中转到V1的路径为8,小于10,修改路径前驱为4。到V2的路径为(5+9)=14 < ∞,修改路径前驱。到V3的距离为5+2=7<∞,修改路径前驱。第一轮处理之后效果如图:
第二轮同理,循环遍历,找到结点V3,与其相连的有V0和V2,V0的final值已经为true了,不用处理,更新V2就可以。
到V3最短路径为7,加上指向V2的边为13 < 14, 更新dist[2]=13, path[2] =3
之后循环同理。处理结束后数组值如图:
求到V2的最短路径:V2的前驱是V1,V1的前驱V4,V4前驱V0,可得到最短路径V0->V4->V1->V2。
时间复杂度
经过n-1轮处理,每次都要遍历所有结点,时间复杂度为O(
n
2
n^2
n2)
迪杰斯特拉算法不适用负权边的情况
Floyd 弗洛伊德算法
初始化一个矩阵,表示各顶点的最短距离,其实就是邻接矩阵名为
A
−
1
A^-1
A−1:
刚开始,都不允许中转,path都设置为-1
首先,我们允许通过V0结点进行中转,V2可通过V0到达V1小于之前的无穷,更新数据如下,
此时得到的矩阵我们称为
A
0
A^0
A0, 在允许通过A1中转,即k=1
允许V2为中转点,最后矩阵为:
若求V0到V2的路径,0到2的path是1,所以0是先到1,再到V2的。
代码实现
因为n个顶点,每个顶点都要遍历一遍矩阵,时间复杂度为O(
n
3
n^3
n3), 空间复杂度为O(
n
2
n^2
n2)
总结
以上是关于最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解的主要内容,如果未能解决你的问题,请参考以下文章
最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解
图的最小生成树和最短路径算法思路总结(Prim,Kruskal,Dijkstra,Floyd)