图的最短路径
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图的最短路径相关的知识,希望对你有一定的参考价值。
无权单源最短路径问题(采用队列的形式和BFS差不多):
利用dist[]和path[]
dist[]用来记录这个点到达源点的距离
path[]用来记录到达这个顶点的路径
默认初始化dist[]为-1.path[]为-1
源点的dist[]为0
如果已经判断过最短路径的点dist[]不为-1path[]为前一个顶点的值
/* 邻接表存储 - 无权图的单源最短路算法 */ /* dist[]和path[]全部初始化为-1 */ void Unweighted ( LGraph Graph, int dist[], int path[], Vertex S ) { Queue Q; Vertex V; PtrToAdjVNode W; Q = CreateQueue( Graph->Nv ); /* 创建空队列, MaxSize为外部定义的常数 */ dist[S] = 0; /* 初始化源点 */ AddQ (Q, S); while( !IsEmpty(Q) ){ V = DeleteQ(Q); for ( W=Graph->G[V].FirstEdge; W; W=W->Next ) /* 对V的每个邻接点W->AdjV */ if ( dist[W->AdjV]==-1 ) { /* 若W->AdjV未被访问过 */ dist[W->AdjV] = dist[V]+1; /* W->AdjV到S的距离更新 */ path[W->AdjV] = V; /* 将V记录在S到W->AdjV的路径上 */ AddQ(Q, W->AdjV); } } /* while结束*/ }
单源有权最短路径问题
Dijkstra算法
辅助数组 collected[]dist[]path[]
每次从未收集的顶点中选择dist[]最小的那个
判断加入这个节点他的邻接点的dist会不会变小如果变小改变邻接点的dist值更新path[]的值
源点的dist[]初始化为0
path[]初始化为-1
其他点的初始化问题
dist[]为源点到这个节点的距离
如果这个点到源点的距离<65535
那么更新他的path[]为前一个点
每次判断插入的点能不能使他的邻接点变小
特殊情况:负值圈问题如果新插入的点到他的邻接点的权值为负数 那么退出循环
Dijkstal算法不能解决带有负值圈的问题
/* 邻接矩阵存储 - 有权图的单源最短路算法 */ Vertex FindMinDist( MGraph Graph, int dist[], int collected[] ) { /* 返回未被收录顶点中dist最小者 */ Vertex MinV, V; int MinDist = INFINITY; for (V=0; V<Graph->Nv; V++) { if ( collected[V]==false && dist[V]<MinDist) { /* 若V未被收录,且dist[V]更小 */ MinDist = dist[V]; /* 更新最小距离 */ MinV = V; /* 更新对应顶点 */ } } if (MinDist < INFINITY) /* 若找到最小dist */ return MinV; /* 返回对应的顶点下标 */ else return ERROR; /* 若这样的顶点不存在,返回错误标记 */ } bool Dijkstra( MGraph Graph, int dist[], int path[], Vertex S ) { int collected[MaxVertexNum]; Vertex V, W; /* 初始化:此处默认邻接矩阵中不存在的边用INFINITY表示 */ for ( V=0; V<Graph->Nv; V++ ) { dist[V] = Graph->G[S][V]; if ( dist[V]<INFINITY ) path[V] = S; else path[V] = -1; collected[V] = false; } /* 先将起点收入集合 */ dist[S] = 0; collected[S] = true; while (1) { /* V = 未被收录顶点中dist最小者 */ V = FindMinDist( Graph, dist, collected ); if ( V==ERROR ) /* 若这样的V不存在 */ break; /* 算法结束 */ collected[V] = true; /* 收录V */ for( W=0; W<Graph->Nv; W++ ) /* 对图中的每个顶点W */ /* 若W是V的邻接点并且未被收录 */ if ( collected[W]==false && Graph->G[V][W]<INFINITY ) { if ( Graph->G[V][W]<0 ) /* 若有负边 */ return false; /* 不能正确解决,返回错误标记 */ /* 若收录V使得dist[W]变小 */ if ( dist[V]+Graph->G[V][W] < dist[W] ) { dist[W] = dist[V]+Graph->G[V][W]; /* 更新dist[W] */ path[W] = V; /* 更新S到W的路径 */ } } } /* while结束*/ return true; /* 算法执行完毕,返回正确标记 */ }
多源最短路径问题:
Floyd算法(每次插入第(0~最大源点数)判断插入这个节点能不能使两个点之间的距离变短)
辅助数组dist[][]path[]
dist[][]初始化问题为两个点之间的权值
/* 邻接矩阵存储 - 多源最短路算法 */ bool Floyd( MGraph Graph, WeightType D[][MaxVertexNum], Vertex path[][MaxVertexNum] ) { Vertex i, j, k; /* 初始化 */ for ( i=0; i<Graph->Nv; i++ ) for( j=0; j<Graph->Nv; j++ ) { D[i][j] = Graph->G[i][j]; path[i][j] = -1; } for( k=0; k<Graph->Nv; k++ ) for( i=0; i<Graph->Nv; i++ ) for( j=0; j<Graph->Nv; j++ ) if( D[i][k] + D[k][j] < D[i][j] ) { D[i][j] = D[i][k] + D[k][j]; if ( i==j && D[i][j]<0 ) /* 若发现负值圈 */ return false; /* 不能正确解决,返回错误标记 */ path[i][j] = k; } return true; /* 算法执行完毕,返回正确标记 */ }
以上是关于图的最短路径的主要内容,如果未能解决你的问题,请参考以下文章