如果给图中的每条边赋一个值,或称权,那么这个图就叫做带权图。
带权图在我们生活中很常见,生活中的交通路线,航班航线,都可以用带权图来表述。而生活中我们常常遇到的问题是,求从一个地点到另一个地点的最短距离,也就是求图中的最短路径问题。
要求这个问题,我们首先要判断图中有没有带负值的弧,如果是带负值,要求其最短路径比较麻烦,因为如果构成了负值圈,就可以一直循环下去,这个大小是∞的。所以本博讨论的最短路径问题,是默认了图中没有负值圈的。
例图
我们将v5设置成起点,v4设置为重点。他的权可以理解为从v5到v4消耗2,从v2到v5获取10,那么就构成了一个负值圈,一直循环下去是没有结果的。
无权图最短路径
因为无权图不带权,所以对其的最短路径的讨论就只和图中所带的边数有关系。所以可以为所有的边都赋值为1。
首先要选取一个起点,起点到起点的值当然是0了。
我们要用到的方法是广度优先搜索(breath-first search)
广度优先搜索BFS : 距开始点最近的那些顶点首先被赋值,而最远的那些顶点最后被赋值。与树的层序遍历有异曲同工之妙。
如图
伪代码实现
void Unweighted(Table T) //Assume T is initiallized
{
int CurrDist;
Vertex V, W;
for(CurrDist = 0; CurrDist < NumVertex; CurrDist++)
{
for each vertex V
if(!T[V].know && T[V].Dist == CurrDist)
{
T[V].know = True;
for each W adjacent to V
if(T[W].Dist == Infinity) //判断其是否无穷大
{
T[W].Dist = CurrDist+1;
T[W].Pash = V;
}
}
}
}
但是上述算法也存在最坏情形,当整个图像链表一样是一条链时,双层循环还是要循环那么多次。之前在讨论拓扑排序时,遇到过类似的情况。这里我们也可以用一个单独的特殊的队列来排除这种低效性。
大概思路是先将顶点压入队列,在出队列时,将还未被标记的,他的下一个邻接点也入队。之后的点重复这样的操作。
void Unweighted(Table T)
{
Queue Q;
Vertex V, W;
Q = CreateQueue(NumVertex); MakeEmpty(Q);
/*EnQueue the start Vertex S, determined elsewhere*/
EnQueue(S, Q);
while(!IsEmpty(Q))
{
V = DeQueue(Q);
T[V].Know = true; //not really needed anymore
for each W adjacent to V
if(T[W].Dist == Infinity)
{
T[W].Dist = T[V].Dist+1;
T[W].Pash = V;
EnQueue(W, Q);
}
}
DisposeQueue(Q); //free the menmory
}