DSAA之图论最短路径问题(BFS)(四)

1. 基础定义

  • 有权路径长度:The input is a weighted graph: associated with each edge ( v i , v j ) is a cost c i , j to traverse the arc. The cost of a path v 1 , v 2 . . . v n is This is referred to as the weighted path length.
  • 无权路径长度:The unweighted path length is merely the number of edges on the path, namely, n 1 .
  • 单源路径问题:Given as input a weighted graph, G = ( V , E ) , and a distinguished vertex, s , find the shortest weighted path from s to every other vertex in G .
  • 负权值圈:negative-cost cycle; when one is present in the graph, the shortest paths are not defined. Negative-cost edges are not necessarily bad, as the cycles are, but their presence seems to make the problem harder. For convenience, in the absence of a negative-cost cycle, the shortest path from s to s is zero.如果图里面有没有负权值圈,(不代表权值为负的边不存在)那么从一个顶点到自身的最短路径为0

2. Unweighted Shortest Paths

  • We are only interested in the number of edges contained on the path, so there are no weights on the edges. This is clearly a special case of the weighted shortestpath problem, since we could assign all edges a weight of 1.无权路径问题是有权路径问题的特例
  • This strategy for searching a graph is known as breadth-first search. It operates by processing vertices in layers: the vertices closest to the start are evaluated first, and the most distant vertices are evaluated last. This is much the same as a level-order traversal for trees.
    BFS类似于树的层序遍历,其保证先找到每个节点最近的其他所有节点,然后依次类推,(因为每次找到相同路径深度下的所有节点,所以叫广度优先搜索)。

  首先目前讨论的最短路径问题都是针对有向图,可以有圈,也可以强弱连通或者不是连通图。然后DSAA有比较具体的算法优化过程,笔者直接按照最优结论记录:

  • We can refine this idea even further by using just one queue. At the start of the pass, the queue contains only vertices of distance curr_dist.
  • When we add adjacent vertices of distance curr_dist + 1, since they enqueue at the rear, we are guaranteed that they will not be processed until after all the vertices of distance curr_dist have been processed.
  • After the last vertex at distance curr_dist dequeues and is processed, the queue only contains vertices of distance curr_dist + 1, so this process perpetuates. We merely need to begin the process by placing the start node on the queue by itself.

  如果用结构体数组存储中间信息,每个结构体成员记录了对应节点距源节点的当前路径长度和该路径上的前一个元素,这个过程其实和二叉树的层序遍历一样,但是这里使用了额外的数组去存储路径长度信息。另外由于Queue先入先出的特点,也正好符合BFS的特点。最后提出两点书上没有提到的细节:

  • 将每个节点对应的dist成员初始化为INT_MAX,在for each w adjacent to v中一定要判断是否该节点dist已经被更新过了,否则可能发生cycle效果
  • 如果while循环终止时,TABLE T中还存在节点dist为INT_MAX,那么证明源节点和这些节点不连通。(这并不代表错误,而是该有向图本来不具有连通性
void unweighted( TABLE T ) /* assume T is initialized (Fig 9.30) */
{
    QUEUE Q;
    vertex v, w;
    Q = create_queue( NUM_VERTEX ); make_null( Q );
    /* enqueue the start vertex s, determined elsewhere */
    enqueue( s, Q );
    while( !is empty( Q ) ){
        v = dequeue( Q );
        for each w adjacent to v
            if( T[w].dist == INT_MAX ){
                T[w].dist = T[v].dist + 1;
                T[w].path = v;
                enqueue( w, Q );
            } 
    }
    dispose_queue( Q );
}

3. 时间复杂度分析

  从上面的伪程序可以直观看到遍历了所有的点和边,所以时间复杂度为 O ( E + V ) ,而因为额外使用了队列和表,所以空间复杂度为 O ( V ) 。具体图论部分的代码实现,会在leetcode遇到实际的问题,再考虑具体实现。

4. 总结

  上述讨论的都是有向图下的最短路径问题,本文特别讨论的是无权最短路径问题。使用了BFS的搜索方法,但是一定要明白这种算法本质是暴力算法。特别的,有向图可以是有圈,也可以是不连通的。最短路径只需查找最终的TABLE,就能得到源节点到目标节点的最短路径长,因为记录了路径中每个节点上一个节点,所以还能打印出该路径。

猜你喜欢

转载自blog.csdn.net/lovestackover/article/details/80560329
今日推荐