Floyd,Dijkstra的详解

来源:互联网 发布:navicat for mysql破解 编辑:程序博客网 时间:2024/06/01 10:00

弗洛伊德算法:

Floyd也就是弗洛伊德算法,是图论中用来计算任意两点间最短路径的算法。

算法的过程是:
1.把图转换成一个带权重的n阶邻接矩阵。
2.依次把1-n的节点当作桥梁,也就是中间点,例如结点u,v和中间结点k,u和v在不经过k结点的时候存在最短   路径x,u经过k结点到达v的时候最短路径为y那么min{x,y}就是在增加k桥梁的时候u和v的最短路径。

Floyd算法执行过程:

例如对于以下的一个有向图,对应的临街矩阵的形式为:



邻接矩阵:


第一步:以定点0作为松弛的点,考虑a[i][j]表示定点i到顶点j经由顶点0的最短路径长度,经过比较,没有任何路径得到修改,因此有:


第二步:以定点1作为松弛的点,考虑a[i][j]表示定点i到顶点j经由顶点1的最短路径长度,经过比较,顶点0到顶点1由原来的没有路径变为0—1—2的路径,其长度为9;因此有:


第三步:以定点2作为松弛的点,考虑a[i][j]表示定点i到顶点j经由顶点2的最短路径长度,经过比较,顶点1到顶点0由原来的没有路径变为1—2—0的路径,其长度为7;

顶点3到顶点0由原来的没有路径变为3—2—0的路径,其长度为4

顶点3到顶点3由原来的没有路径变为3—2—1的路径,其长度为4因此有:



第四步:以定点3作为松弛的点,考虑a[i][j]表示定点i到顶点j经由顶点3的最短路径长度,经过比较,顶点0到顶点2由原来的路径长度为9,路径为 0—1—2,变为0—3—2,其长度为8;

顶点1到顶点0由原来的路径长度为7,路径为1—2—0,变为1—3—2—0,其长度为6;

顶点1到顶点2由原来的路径长度为4,路径为1—2 ,变为1—3—2 ,其长度为3;


如果设n为图中顶点的个数,则弗洛伊德的代码实现:

void floyd(){    for(k=0;k<n;k++)        for(i=0;i<n;i++)            for(j=0;j<n;j++)                A[i][j]=min(A[i][j],A[i][k]+A[k][j]);}

其最基本的理解就是在原来经过前k-1的前提下,如果经过k会不会对原来的格局产生影响,原来的状态已经是可计算出来的。桥梁的含义就是能否提供一条更短的捷径。
时间复杂度因为有三重循环明显是:O(n3 )。

本题为运用Floyd求最小环问题

迪杰斯特拉算法:

Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法能得出最短路径的最优解,但由于它遍历计算的节点很多,所以效率低。

第一种方法:

假定现有一公交网络如图3.1所示。假设该网络中任意一对有直接通路的顶点间的通路都是双向可行的,则可以将其抽象为一个无向带权图,并且各相邻顶点间的直接距离如表3.1所示,现要求解的问题是:寻找从A点出发到达其他各顶点的最短路径。根据Dijkstra算法,可得出搜索过程和结果如表3.2所示,运用MATLAB编程的结果见附录。

图3.1 公交网络

从表3.2可以看出,从A点出发到达其它各顶点的最短路径,按递增顺序依次为AC(2km),AB(3km),ACD(4km),ACE(5km),ACDF(7km),ACEFG(11km)。

在实际应用中如果只是为了寻找两个指定顶点之间的最短路径,则可以给每个顶点赋予一个未访问标号(F)或已访问标号(T)。F表示从起始点到目的点之间还未找到最短路径,T表示从起始点到目的点之间已找到最短路径。这样每一次计算的目的是为了找到某个顶点将其F标号变成T标号,一旦目的顶点的标号变成T,则表示已寻找到从起始点到目的点之间的最短路径搜寻计算过程即可停止。例如,在上述实例中,如果只需求解从A点到达E点的最短路径,则搜寻会在A点、C点、B点、D点、E点的标号依次变成T之后结束,即 E点标号变成T后表示到达E点的最短路径已找到。

表3.1 无向图的边权列表

路段

距离(km)

路段

距离(km)

AB

3

CF

7

AC

2

DE

5

AD

5

DF

6

BC

2

DG

10

BE

4

EF

2

BF

5

EG

7

CD

2

FG

4

CE

3

 

 

 

 表3.2 最短路径算法的搜索过程和结果

   

步骤

集合S

源点到各个顶点的距离

最小距离值

待加入顶点

D[A]

D[B]

D[C]

D[E]

DE]

D[F]

D[G]

1

A

0

3

2

5

2

C

2

A,C

0

3

2

2+2=4

2+3=5

2+7=9

3

B

3

A,C,B

0

3

2

4

5

3+5=8

4

D

4

A,C,B,D

0

3

2

4

5

8

4+10=14

5

E

5

A,C,B,D,E

0

3

2

4

5

5+2=7

5+7=12

7

F

6

A,C,B,D,E,F

0

3

2

4

5

7

7+4=11

11

G

7

A,C,B,D,E,F,G

0

3

2

4

5

7

11

 

 


第二种方法:

1.有向带权图

本篇博客依然采取我们之前用的图的结构。不过我们本篇博客使用的是有向图。下方这张图就是是我们之前使用的无向图转换过来的,只是给之前的图的边添加的具体的方向,其他的并为改动。由无向图转换后的有向图如下所示,我们将在下方的图的基础上计算出从A到D的最短路径


2.迪杰斯特拉算法的具体步骤

下图就是求上图中A->D的最短路径时使用迪杰斯特拉算法的具体步骤。迪杰斯特拉算法主要核心思想是由起始结点开始,慢慢的由尾结点扩散。直到扩展到尾结点位置。下方我们将根据每个步骤给出具体的介绍:



  • (1)与起始结点A直接相连的点是B和F, 即A->B的距离为10A->F的距离为11, 所以我们选择A->B这个路径。
  • (2)选择B结点后,我们开始探测与B相连的结点,即A->B->G路径长度为26A->B->I路径长度为22A->B->C路径长度为28,这三个与上一步留下的A->F(11)相比,A->F(11)的距离最短,所以接下来要探测与F相连的结点。
  • (3)F可到达的点是G和E,所以A->F->G的距离为27,A->F->E的距离为37。因为A->F->G(27) 大于A->B->G(26)这个路径,所以由A到G的路径我们依然选择A->B->G(26)这个路径。从A->B->G(26),A->B->I(22),A->B->C(28), A->F->E(37)。中选出最短那个距离就是A->B->I(22),所以我们将I作为我们下次探测的结点。
  • (4)与I相连的就是D结点,所以我们容易计算出A->B->I->D这条路径的长度为22+21=43。从A->B->I->D(43), A->B->G(26), A->B->C(28), A->F->E(37)这些路径中我们还是选择最小的那一个,不难看出A->B->G(26)这条路径在上述路径集合中最小,所以我们将G结点作为下次路径的探测对象。
  • (5)G可到达的结点是H和D, 所以我们可以得到两条新的路径A->B->G->H(26+19=45)A->B->G->D(26+24=50),因为A->B->G->D(50)这条路径的长度要大于A->B->I->D(43)这条路径的长度,因为这两条路径都是从A到D,所以我们选择较小的A->B->I->D(43)路径。从A->B->G->H(45),A->B->I->D(43), A->B->C(28), A->F->E(37)这几条路径中我们依然选择最小的那条路径。从上面这几条数据我们不难看出 A->B->C(28)这条路径最短,所以我们下次要探测的点是C点。
  • (6)C点可以到达的点只有D点,所以我们可以得到一条新的路径A->B->C->D, 路径长度为50。因为从A到达D的路径还有A->B->I->D(43),而A->B->C->D(50)这条路径的长度要大一些,A到D点的路径依然选择A->B->I->D(43)。C结点探测完毕,我们从A->B->G->H(45),A->B->I->D(43), A->F->E(37)几条候选路径中依然选择最小的那一个。不难看出 A->F->E(37)这条路径最小,所以下一步我们要探测E结点。
  • (7)E结点可以到达的点为H和D,所以A->F->E(37)这条路径可以延伸为A->F->E->H(44)和A->F->E->G(57)两条边。因为A到H的路径还有一条为A->B->G->H(45),而我们刚生出的这一条要小于之前的那一条,所以A到H的路径更新为A->F->E->H(44)。而A->F->E->G(57)这条A到D的路径要比A->B->I->D(43)要大,所以不进行更新,A到D的路径依然采用A->B->I->D(43)。经过这一步后我们将A->F->E->H(44)和A->B->I->D(43)进行比较,较小的路径为A->B->I->D(43),而D节点又是我们的终点,所以A到D的最短路径为A->B->I->D(43)
3.迪杰斯特拉算法的数据表示

上面是我们使用图形的方式给出了迪杰斯特拉算法的具体步骤,接下来我们会把上面的步骤转换成数据的表示方式,以便于我们使用程序进行计算。下方就是上面这些示意图的的完整的数据表示。下方矩阵中的数据标志着起始节点到该节点的距离。由上到下,以此增加距离的大小,而最上面一排的红色字母,标示着该结点的前驱。下方我们在给出每一个行数据的详细介绍。

  • 第一行数据记录了A->B和A->F的信息,当然A->A的距离为0。其他尚不可达的点为-1。
  • 第二行在第一行数据的基础上证据了A->B->C, A->B->G, A->B->I的距离信息,因为从第一行数的比较我们可以知道,A->B的距离要小于A->F的距离,所以我们的最短路径要向着A->B->?上发展。
  • 第三行的数据则是在第二行的数据上得到的,从第二行数据上我们容易看出,A->F(11)要比A->B->(C, G, I)都要小,所以我们的最短路径要向着A->F->?的放心发展。所以我们找到了A->F->E(37)和A->F->G(28)这条路径。因为A->B->G(26)小于A->F->G(28),所以A到G的路径不进行更新。
  • 第四行的数据则是第三行数据的延伸,我们可以知道A->B->I(2)在当前所有延伸的路径中最小,所以我们要向着A->B->I->? 方向发展。因此我们找到了A->B->I->D(43)这条路径。
  • 以此类推……

总结

  • 第一步:比较已经发展的所有路径,找出目前最短的路径。
  • 第二步:在上一步找到的最短路径的基础上发展新的路径,然后重复上一步,直到延伸到end节点为止。
运用dis的题,有详细说明

原创粉丝点击