最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解

最小生成树

Prim(普雷姆)算法

以某一个顶点开始构建生成树,每次将代价最小的新顶点纳入生成树,直到所有顶点都纳入位置。设有如下图:
从P点开始构建生成树,选择其他顶点也可
最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解_第1张图片
首先与P相连最小的代价(边)是学校,代价为1,将其并入:
最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解_第2张图片
此时与生成树相连的边有5,6,5,4,6,4,最小的代价时连渔村或者矿场,我们这里选择连矿场,选渔村的话生成的最小生成树代价不变,所以同一个图可以有多个最小生成树此时最小树生成树如图:
最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解_第3张图片
再选择代价最小的顶点并入生成树,依此类推,最小生成树:
最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解_第4张图片

Kruskal (克鲁斯卡尔)算法

每次选择一条权值最小的边,使这条边的两头联通(原本已经联通的就不选),直到所有结点都联通。
还是上面的例子:
首先选出权值最小的一条边,显然是1,使连通。
最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解_第5张图片
再选出权值最小的边,<渔村,矿场>权值为2,使连通
最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解_第6张图片
再次选择权值最小的边,显然为<农场,电站>3
最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解_第7张图片
再次重复上述步骤发现,权值最小的边有两个,4,4,而P城与这两个边均为连通,我们随便选一条,假设选择4:
最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解_第8张图片
此时P城,矿场,渔村,是连通的,不能再选择4这条边了,同理不能选择<学校,矿场>5,而是选择<农场,P城>5边。最小生成树与普雷姆算法一致。

对比

最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解_第9张图片

最短路径问题

单源最短路径:即求图中某一顶点到其他各顶点的最短路径。
使用广度优先搜索(BFS)可以实现对无权图的单源最短路径的求解。
但对于有权图来说BFS不在适用,可考虑迪杰斯特拉算法求单源路径长度,求各顶点的最短路径考虑弗洛伊德算法。

Dijkstra(迪杰斯特拉)算法

设有以下图,求V0的单源最短路径:
初始化,发现从V0可以直接到V1, V4。dist[1]表示此刻能找到的从V0到V1的最短路径,V2,V3因为不存在直接和V1相连的边,所以dist为无穷大。path表示路径结点前驱,我们此时最短路径10,5都是由V0直接指向的,所以V1,V4的前驱自然为0(V0)。
最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解_第10张图片
第一轮循环:找到还没确定最短路径(即final值为false,dist最小的顶点),顶点V4,将其设置为true,
为什么要将V4设为true?已经找到了V0到V4的最短路径了吗?是的,因为我们选择的是与V0相邻的,边权值最小的顶点,如果路径通过V1中转最小,那么第一轮循环选择的顶点应该是V1而不是V4.
最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解_第11张图片
检查所有邻接V4的顶点,若其值为false,更新它的dist和path数组信息。如何更新?以V1为例子,检查到V1的路径长度通过V4中转权值会不会更小。V0通过V4中转到V1的路径为8,小于10,修改路径前驱为4。到V2的路径为(5+9)=14 < ∞,修改路径前驱。到V3的距离为5+2=7<∞,修改路径前驱。第一轮处理之后效果如图:
最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解_第12张图片
第二轮同理,循环遍历,找到结点V3,与其相连的有V0和V2,V0的final值已经为true了,不用处理,更新V2就可以。
最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解_第13张图片
到V3最短路径为7,加上指向V2的边为13 < 14, 更新dist[2]=13, path[2] =3
之后循环同理。处理结束后数组值如图:
最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解_第14张图片
求到V2的最短路径:V2的前驱是V1,V1的前驱V4,V4前驱V0,可得到最短路径V0->V4->V1->V2。

时间复杂度

经过n-1轮处理,每次都要遍历所有结点,时间复杂度为O( n 2 n^2 n2
迪杰斯特拉算法不适用负权边的情况

Floyd 弗洛伊德算法

初始化一个矩阵,表示各顶点的最短距离,其实就是邻接矩阵名为 A − 1 A^{-1} A1
刚开始,都不允许中转,path都设置为-1
最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解_第15张图片
首先,我们允许通过V0结点进行中转,V2可通过V0到达V1小于之前的无穷,更新数据如下,
最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解_第16张图片
此时得到的矩阵我们称为 A 0 A^{0} A0, 在允许通过A1中转,即k=1
最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解_第17张图片
允许V2为中转点,最后矩阵为:
最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解_第18张图片
若求V0到V2的路径,0到2的path是1,所以0是先到1,再到V2的。
代码实现
最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解_第19张图片
因为n个顶点,每个顶点都要遍历一遍矩阵,时间复杂度为O( n 3 n^{3} n3), 空间复杂度为O( n 2 n^{2} n2)
最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解_第20张图片

总结

最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解_第21张图片

你可能感兴趣的:(最小生成树(Prim,Kruskal)--最短路径(Dijkstra,Floyd)算法详解)