24
第 18 第 第第第 第第 ()

第 18 讲 第七章 图(四)

  • Upload
    tanner

  • View
    91

  • Download
    0

Embed Size (px)

DESCRIPTION

第 18 讲 第七章 图(四). 7.7 最短路径 7.7.1 路径的概念 在一个无权的图中 , 若从一顶点到另一顶点存在着一条路径 , 则称该路径长度为该路径上所经过的边的数目 , 它等于该路径上的顶点数减 1 。由于从一顶点到另一顶点可能存在着多条路径 , 每条路径上所经过的边数可能不同 , 即路径长度不同 , 我们把路径长度最短 ( 即经过的边数最少 ) 的那条路径叫做最短路径 , 其路径长度叫做最短路径长度或最短距离。. - PowerPoint PPT Presentation

Citation preview

Page 1: 第 18 讲 第七章  图(四)

第 18讲 第七章 图(四)

Page 2: 第 18 讲 第七章  图(四)

7.7 最短路径

7.7.1 路径的概念

在一个无权的图中 , 若从一顶点到另一顶点存在着一条路径 , 则称该路径长度为该路径上所经过的边的数目 , 它等于该路径上的顶点数减 1 。由于从一顶点到另一顶点可能存在着多条路径 , 每条路径上所经过的边数可能不同 , 即路径长度不同 ,我们把路径长度最短 ( 即经过的边数最少 ) 的那条路径叫做最短路径 , 其路径长度叫做最短路径长度或最短距离。

Page 3: 第 18 讲 第七章  图(四)

对于带权的图 , 考虑路径上各边上的权值 ,则通常把一条路径上所经边的权值之和定义为该路径的路径长度或称带权路径长度。从源点到终点可能不止一条路径 , 把带权路径长度最短的那条路径称为最短路径 , 其路径长度 ( 权值之和 ) 称为最短路径长度或者最短距离。

Page 4: 第 18 讲 第七章  图(四)

7.7.2 从一个顶点到其余各顶点的最短路径

问题:给定一个带权有向图 G 与源点 v,

求从 v 到 G 中其他顶点的最短路径 , 并限定各边上的权值大于或等于 0 。

Page 5: 第 18 讲 第七章  图(四)

采用狄克斯特拉 (Dijkstra) 算法求解 基本思想是:设 G=(V,E) 是一个带权有向图 , 把图中顶点集合 V 分成两组: 第一组为已求出最短路径的顶点集合 ( 用 S 表示 , 初始时 S 中只有一个源点 , 以后每求得一条最短路径 v,…vk, 就将 vk 加入到集合 S 中 , 直到全部顶点都加入到 S 中 , 算法就结束了 )

第二组为其余未确定最短路径的顶点集合 ( 用U 表示 ) 。 按最短路径长度的递增次序依次把第二组的顶点加入 S 中。在加入的过程中 , 总保持从源点 v 到 S中各顶点的最短路径长度不大于从源点 v 到 U 中任何顶点的最短路径长度。此外 , 每个顶点对应一个距离 ,S中的顶点的距离就是从 v 到此顶点的最短路径长度 ,U中的顶点的距离从 v 到此顶点只包括 S 中的顶点为中间顶点的当前最短路径长度。

Page 6: 第 18 讲 第七章  图(四)

狄克斯特拉算法的具体步骤如下:

(1) 初始时 ,S 只包含源点 , 即 S={v},v 的距离为 0 。U 包含除 v 外的其他顶点 ,U 中顶点 u 距离为边上的权( 若 v 与 u 有边 <v,u>) 或∞ ( 若 u 不是 v 的出边邻接点 ) 。

(2) 从 U 中选取一个距离 v 最小的顶点 k, 把 k 加入 S中 ( 该选定的距离就是 v 到 k 的最短路径长度 ) 。

(3) 以 k 为新考虑的中间点 , 修改 U 中各顶点的距离:若从源点 v 到顶点 u(u U)∈ 的距离 ( 经过顶点 k) 比原来距离 ( 不经过顶点 k) 短 , 则修改顶点 u 的距离值 , 修改后的距离值的顶点 k 的距离加上边 <k,u> 上的权。

(4) 重复步骤 (2) 和 (3) 直到所有顶点都包含在 S 中。

Page 7: 第 18 讲 第七章  图(四)

1 4

0 2 6

3 5 8

1

6 6

4 2

5

6

6

1 4

7

S U v0 到 0 ~ 6 各顶点的距离{0} {1,2,3,4,5,6} {0,4,6,6,∞,∞,∞}

{0,1} {2,3,4,5,6} {0,4,5,6,11,∞,∞}

{0,1,2} {3,4,5,6} {0,4,5,6,11,9,∞}

{0,1,2,3} {4,5,6} {0,4,5,6,11,9,15}

{0,1,2,3,5} {4,6} {0,4,5,6,10,9,17}

{0,1,2,3,5,4} {6} {0,4,5,6,10,9,16}

{0,1,2,3,5,4,6} {} {0,4,5,6,10,9,16}

则 v0 到 v1 ~ v6 各顶点的最短距离分别为 4 、5 、 6 、 10 、 9 和 16 。

Page 8: 第 18 讲 第七章  图(四)

狄克斯特拉算法如下 (n 为图 G 的顶点数 ,v0 为源点编号 ) :void Dijkstra(int cost[][MAXV],int n,int v0)

{ int dist[MAXV],path[MAXV]; int s[MAXV];int mindis,i,j,u;

for (i=0;i<n;i++)

{ dist[i]=cost[v0][i]; /* 距离初始化 */

s[i]=0; /*s[] 置空 */

if (cost[v0][i]<INF) /* 路径初始化 */

path[i]=v0;

else

path[i]=-1;

}

s[v0]=1;path[v0]=0; /* 源点编号 v0 放入 s 中 */

Page 9: 第 18 讲 第七章  图(四)

for (i=0;i<n;i++) /* 循环直到所有顶点的最短路径都求出 */

{ mindis=INF;

u=-1;

for (j=0;j<n;j++) /* 选取不在 s 中且具有最小距离的顶点 u*/

if (s[j]==0 && dist[j]<mindis)

{ u=j; mindis=dist[j]; }

s[u]=1; /* 顶点 u 加入 s 中 */

for (j=0;j<n;j++) /* 修改不在 s 中的顶点的距离 */

if (s[j]==0)

if (cost[u][j]<INF && dist[u]+cost[u][j]<dist[j])

{ dist[j]=dist[u]+cost[u][j]; path[j]=u; }

}

Dispath(dist,path,s,n,v0); /* 输出最短路径 */

}

Page 10: 第 18 讲 第七章  图(四)

void Ppath(int path[],int i,int v0) /* 前向递归查找路径上的顶点 */

{ int k;

k=path[i];

if (k==v0) return; /* 找到了起点则返回 */

Ppath(path,k,v0); /* 找 k 顶点的前一个顶点 */

printf("%d,",k); /* 输出 k 顶点 */

}

Page 11: 第 18 讲 第七章  图(四)

void Dispath(int dist[],int path[],int s[],int n,int v0)

{ int i;

for (i=0;i<n;i++)

if (s[i]==1)

{ printf(“ 从 %d 到 %d 的最短路径长度为 :

%d\t 路径为 :",v0,i,dist[i]);

printf("%d,",v0); /* 输出路径上的起点 */

Ppath(path,i,v0); /* 输出路径上的中间点 */

printf("%d\n",i); /* 输出路径上的终点 */

}

else printf(" 从 %d 到 %d 不存在路径 \n",v0,i);

}

Page 12: 第 18 讲 第七章  图(四)

7.7.3 每对顶点之间的最短路径

问题:对于一个各边权值均大于零的有向图 ,

对每一对顶点 vi≠vj, 求出 vi 与 vj 之间的最短路径和最短路径长度。

可以通过以每个顶点作为源点循环求出每对顶点之间的最短路径。除此之外 , 弗洛伊德 (Floyd)

算法也可用于求两顶点之间最短路径。

Page 13: 第 18 讲 第七章  图(四)

假设有向图 G=(V,E) 采用邻接矩阵 cost

存储 , 另外设置一个二维数组 A 用于存放当前顶点之间的最短路径长度 , 分量 A[i][j] 表示当前顶点 vi 到顶点 vj 的最短路径长度。弗洛伊德算法的基本思想是递推产生一个矩阵序列 A0,A1,…,Ak,…,An, 其中 Ak[i][j]

表示从顶点 vi 到顶点 vj 的路径上所经过的顶点编号不大于 k 的最短路径长度。

Page 14: 第 18 讲 第七章  图(四)

初始时 , 有 A-1[i][j]=cost[i][j] 。当求从顶点 vi

到顶点 vj 的路径上所经过的顶点编号不大于 k+1 的最短路径长度时 , 要分两种情况考虑:

一种情况是该路径不经过顶点编号为 k+1 的顶点 , 此时该路径长度与从顶点 vi 到顶点 vj 的路径上所经过的顶点编号不大于 k 的最短路径长度相同;

另一种情况是从顶点 vi 到顶点 vj 的最短路径上经过编号为 k+1 的顶点。

那么 , 该路径可分为两段 , 一段是从顶点 vi 到顶点 vk+1 的最短路径 , 另一段是从顶点 vk+1 到顶点 vj

的最短路径 , 此时最短路径长度等于这两段路径长度之和。这两种情况中的较小值 , 就是所要求的从顶点 v

i 到顶点 vj 的路径上所经过的顶点编号不大于 k+1 的最短路径。

Page 15: 第 18 讲 第七章  图(四)

弗洛伊德思想可用如下的表达式来描述: A-1[i][j]=cost[i][j]

Ak+1[i][j]=min{Ak[i][j],Ak[i][k+1]+Ak[k+1][j]} (0≤k≤n-1)

Page 16: 第 18 讲 第七章  图(四)

0 1

2 3

1

2

7

2 3 4 3

5

01

2033

240

750

01

2033

240

750

A 1

1111

1111

1111

1111

Path 1

采用弗洛伊德算法求解过程

Page 17: 第 18 讲 第七章  图(四)

考虑顶点 v0,A0[i][j] 表示由 vi

到 vj, 经由顶点 v0 的最短路径。只有

从 v2 到 v1 经过 v0 的路径和从 v2 到 v3

经过 v0 的路径 , 不影响 v2 到 v1 和 v2

到 v3 的路径长度 , 因此 , 有:

01

2033

240

750

A0

1111

1111

1111

1111

Path0

0 1

2 3

1

2

7

2 3 4 3

5

Page 18: 第 18 讲 第七章  图(四)

考虑顶点 v1,A1[i][j] 表示由 vi

到 vj, 经由顶点 v1 的最短路径。

存在路径 v0-v1-v2, 路径长度为 9,

将 A[0][2] 改为 9,path[0][2] 改为 1, 因此 , 有:

01

2033

240

7950

A1

1111

1111

1111

1111

Path1

0 1

2 3

1

2

7

2 3 4 3

5

Page 19: 第 18 讲 第七章  图(四)

考虑顶点 v2,A2[i][j] 表示由 vi 到 vj,

经由顶点 v2 的最短路径。存在路径v3-v2-v0, 长度为 4, 将 A[3][0] 改为 4 ;存在路径 v3-v2-v1, 长度为 4, 将 A[3]

[1] 改为 4 。存在路径 v1-v2-v0, 长度为 7, 将 A[1][0] 改为 7 。将 path[3]

[0] 、 path[3][1] 和 path[1][0] 均改为 2 。因此 , 有:

0144

2033

2407

7950

A2

1122

1111

1112

1111

Path 2

0 1

2 3

1

2

7

2 3 4 3

5

Page 20: 第 18 讲 第七章  图(四)

考虑顶点 v3,A3[i][j] 表示由 vi

到 vj, 经由顶点 v3 的最短路径。存在路径 v0-v3-v2, 长度为 8 比原长度短 ,

将 A[0][2] 改为 8 ;存在路径 v1-v3-v2-

v0, 长度为 6(A[1][3]+A[3][0]=2+4=6)

比原长度短 , 将 A[1][0] 改为 6 ;存在路径 v1-v3-v2, 长度为 3, 比原长度短 ,

将 A[1][2] 改为 3 ;将 path[0][2] 、 path[1][0] 后 path[1][2] 均改为 3 。因此 , 有:

0144

2033

2306

7850

A3

1122

1111

1313

1311

3Path

0 1

2 3

1

2

7

2 3 4 3

5

Page 21: 第 18 讲 第七章  图(四)

因此 , 最后求得的各顶点最短路径长度 A 和Path 矩阵为:

0144

2033

2306

7850

从 0 到 0 路径为: 0,0 路径长度为: 0

从 0 到 1 路径为: 0,1 路径长度为: 5

从 0 到 2 路径为: 0,3,2 路径长度为: 8

从 0 到 3 路径为: 0,3 路径长度为: 7

从 1 到 0 路径为: 1,3,2,0 路径长度为: 6

从 1 到 1 路径为: 1,1 路径长度为: 0

从 1 到 2 路径为: 1,3,2 路径长度为: 3

从 1 到 3 路径为: 1,3 路径长度为: 2

1122

1111

1313

1311

Page 22: 第 18 讲 第七章  图(四)

从 2 到 0 路径为: 2,0 路径长度为: 3

从 2 到 1 路径为: 2,1 路径长度为: 3

从 2 到 2 路径为: 2,2 路径长度为: 0

从 2 到 3 路径为: 2,3 路径长度为: 2

从 3 到 0 路径为: 3,2,0 路径长度为: 4

从 3 到 1 路径为: 3,2,1 路径长度为: 4

从 3 到 2 路径为: 3,2 路径长度为: 1

从 3 到 3 路径为: 3,3 路径长度为: 0

Page 23: 第 18 讲 第七章  图(四)

弗洛伊德算法如下:void Floyd(int cost[][MAXV],int n)

{ int A[MAXV][MAXV],path[MAXV][MAXV];int i,j,k;

for (i=0;i<n;i++)

for (j=0;j<n;j++)

{ A[i][j]=cost[i][j]; path[i][j]=-1; }

for (k=0;k<n;k++)

for (i=0;i<n;i++)

for (j=0;j<n;j++)

if (A[i][j]>(A[i][k]+A[k][j]))

{ A[i][j]=A[i][k]+A[k][j]; path[i][j]=k; }

Dispath(A,path,n); /* 输出最短路径 */

}

Page 24: 第 18 讲 第七章  图(四)

本讲小结

本讲基本学习要点如下:(1) 掌握图的最短路径算法。(2) 灵活运用图这种数据结构解决一些综合应用问题。