最短路径-Dijkstra

来源:互联网 发布:sql外键级联删除 编辑:程序博客网 时间:2024/06/05 21:11

首先,提出两点:一、如果把不带权图上的所有边的权值均定义为1,则该不带权图可以归结为带权图;二、如果把无向图中的每一条边(vi,vj)都定义为弧<vi,vj>和弧<vj,vi>,则该无向图可以归结为有向图。因此不失一般性,我们只用看有向带权图怎么求解最短路径问题就ok。

带权图中,从一个结点到另个一结点存在着多条路径,称每一条路径上所经过边的权值之和为该路径上的带权路径长度,那么在两个结点间的所有路径中,路径长度值最小的称做最短路径(距离)。

对于有向带权图中从一个确定结点(源点)到其余各结点的最短路径问题,狄克斯特拉(Dijkstra)提出了一个按照路径长度递增的顺序逐步产生最短路径的构造算法。

Dijkstra算法:设置两个结点的集合S和T,集合S中存放已找到最短路径的结点,集合T存放当前还未找到最短路径的结点。(1)初始状态,S只包含源点,设为v0;(2)然后从T中选择出由源点v0到其中某一结点路径长度最短的结点u,加入到集合S中;(3)集合S中每加入一个新的结点u都要修改源点v0到集合T中剩余结点的当前最短路径长度值;(4)那么这最小的当前最短路径长度值为,原来的当前最短路径长度值和从源点v0过结点u到到达该结点的路径长度相比,取小的那个值。(5)不断重复,知道集合T中的结点全部加入到集合S中为止。

接下来实现算法:

package Map;/*** @author sun* 创建时间:2017年5月11日下午5:02:17*///dijkstra类和函数设计public class Dijkstra {static final int maxWeight = 9999;public static void dijkstra(AdjMWGraph g,int v0,int[] distance,int[] path)throws Exception{//带权图g从下标v0结点到其他结点的最短距离distance//和相应的目标结点的前一结点下标pathint n = g.getNumOfVertices();int[] s = new int[n];//s用来存放n个结点的标记int minDis,u=0;//u为目标结点下标//初始化for(int i=0;i<n;i++){distance[i] = g.getWeight(v0, i);s[i] = 0;//初始标记为0if(i!=v0 && distance[i]<maxWeight)path[i] = v0;//初始的目标结点的前一结点均为v0elsepath[i] = -1;}s[v0] = 1;//标记结点v0已从集合T加入到集合S中//在当前还未找到最短路径的结点集合中选取具有最短距离的结点ufor(int i=1;i<n;i++){minDis = maxWeight;for(int j=0;j<n;j++)if(s[j]==0 && distance[j]<minDis){u = j;minDis = distance[j];}//当已不存在路径时算法结束;此语句对非连通图是必需的if(minDis==maxWeight) return;s[u] = 1;//标记结点u已从集合T加入到集合S中//修改从v0到其他结点的最短距离和最短路径for(int j=0;j<n;j++)if(s[j]==0 && g.getWeight(u, j)<maxWeight && distance[u]+g.getWeight(u, j)<distance[j]){//结点v0经结点u到其他结点的最短距离和最短路径distance[j] = distance[u]+g.getWeight(u, j);path[j] = u;}}}}

对下图进行测试:


package Map;/*** @author sun* 创建时间:2017年5月11日下午5:39:55*/public class TestDijkstra {static final int maxVertices = 100;//构造图public static void createGraph(AdjMWGraph g,Object[] v,int n,RowColWeight[] rc,int e)throws Exception{for(int i=0;i<n;i++)g.insertVertex(v[i]);for(int k=0;k<e;k++)g.inserEdge(rc[k].row,rc[k].col, rc[k].weight);}public static void main(String[] args) {AdjMWGraph g = new AdjMWGraph(maxVertices);Character[] a = {new Character('A'),new Character('B'),new Character('C'),new Character('D'),new Character('E'),new Character('F')};RowColWeight[] rcw = {new RowColWeight(0,2,5),new RowColWeight(0,3,30),new RowColWeight(1,0,2),new RowColWeight(1,4,8),new RowColWeight(2,1,15),new RowColWeight(2,5,7),new RowColWeight(4,3,4),new RowColWeight(5,3,10),new RowColWeight(5,4,18)};int n = 6,e = 9;try{createGraph(g,a,n,rcw,e);int[] distance = new int[n];int[] path = new int[n];Dijkstra.dijkstra(g, 0, distance, path);System.out.println("从顶点A到其他各顶点的最短距离为: ");for(int i=1;i<n;i++)System.out.println("到顶点"+g.getValue(i)+"的最短距离为:"+distance[i]);System.out.println("从顶点A到其他各顶点的前一顶点分别为:");for(int i=0;i<n;i++)if(path[i]!=-1)System.out.println("到顶点"+g.getValue(i)+"的前一顶点为:"+g.getValue(path[i]));}catch(Exception ex){ex.printStackTrace();}}}/*从顶点A到其他各顶点的最短距离为: 到顶点B的最短距离为:20到顶点C的最短距离为:5到顶点D的最短距离为:22到顶点E的最短距离为:28到顶点F的最短距离为:12从顶点A到其他各顶点的前一顶点分别为:到顶点B的前一顶点为:C到顶点C的前一顶点为:A到顶点D的前一顶点为:F到顶点E的前一顶点为:B到顶点F的前一顶点为:C */

求每对结点之间的最短路径,若利用Dijkstra算法(时间复杂度为O(n^2)),就是每次以不同的结点作为源点,求解该源点到其余结点的最短路径。那么,求该问题的算法时间复杂度为O(n^3)。

对于此问题,弗洛伊德(Floyd)提出了一种递推的算法来求解,即弗洛伊德算法。

用矩阵cost[i][j]来存放图G中下标为i的结点到下标为j的结点之间的权值,那么可以通过递推构造一个矩阵序列A0,A1,···,AN来求每对结点之间的最短路径。其中,Ak[i][j](0<k<n)表示从结点vi到结点vj的路径上所经过的结点下标不大于k的最短路径长度。

弗洛伊德算法的思想可用地推公式描述:


0 0
原创粉丝点击