最短路问题的抽象.
在网络中,求两个不同顶点之间的所有路径中,边的权值之和最小的那一条路径.
这条路径就是两点之间的最短路径.
第一个顶点为源点.
最后一个顶点为终点.
单源最短路问题:从某个固定点出发,求到其他所有点的最短路径问题.
(有向)无权图
(有向)有权图
多源最短路问题:求任意两个顶点之间的最短路径.
按照递增(非递减)的顺序找到各个顶点的最短路
无权图的单源最短路问题:
dist[W] = S到W的最短距离
void Unweighted(Vertex S)
{
Enqueue(S,Q);
while(!IsEmpty(Q)){
V = Dequeue(Q);
for(V的每个邻接点W)
if(dist[W] == -1){
dist[W] = dist[V] + 1;
path[W] = V;
Enqueue(W,Q);
}
}
}
有权图的单源最短路问题:
Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。注意该算法要求图中不存在负权边。
算法描述:
算法思想:设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径 , 就将加入到集合S中,直到全部顶点都加入到S中,算法就结束了),第二组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入S中。在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到U中任何顶点的最短路径长度。此外,每个顶点对应一个距离,S中的顶点的距离就是从v到此顶点的最短路径长度,U中的顶点的距离,是从v到此顶点只包括S中的顶点为中间顶点的当前最短路径长度
代码实现
//邻接矩阵存储 - 有权图的单源最短路算法
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){
//若未被收录,且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];
path[V] = -1;
collected[V] = false;
}
//先将起点收入集合
dist[S] = 0;
collected[S] = true;
while(1){
// V = 未被收录顶点中dist最小者
V = FindMinDist(Graph,dist,collected);
if(V == ERROR)
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[W] + Graph->G[V][W];
path[W] = V;//更新S到W的路径
}
}
}
}
return true;
}
多源最短路算法:
方法一:直接将单源最短路算法调用|V|遍 (对于稀疏图使用)
方法二:Floyd算法
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];
}
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]){
if(i==j&&D[i][j])//如果发现负值圈
return false;
path[i][j] = k;
}
return false;
}