DSAA之图论Graphs with Negative Edge Costs(六)

1. 回顾

  回顾以前的知识:拓扑排序,其用于有向无圈图(DAG),无关连通性。为了解决单源最短路径问题,首先学习了广度优先搜索(BFS),其用于有向无权图,无关有圈无圈或者连通,根据这点BFS也可以用于无向图。接着针对有向带权图(权值非负),使用Dijkstra算法解决最短路径问题。
  本文继续学习对于有向带权图存在负值边的情况,如何解决单源最短路径问题。当然DSAA在本节的描述非常有限,可以参考其他资料深入理解。

2. 分析

If the graph has negative edge costs, then Dijkstra’s algorithm does not work. The problem is that once a vertex u is declared known, it is possible that from some other, unknown vertex v there is a path back to u that is very negative. In such a case, taking a path from s to v back to u is better than going from s to u without using v.

  这里写图片描述
  理解上面在说什么,最好自己画个图。Dijkstra算法处理上图的时候可能会有两种选择,因为1-2和1-3的权重一样,如果先处理2的话,得到1-2-3的最短路径,当然这是没有问题的。但是如果先处理3的话,得到1-3,1-2的结果,Dijkstra算法就算错了。当然笔者也认为那么每次选择未知点中dv值最小的点的时候稍加处理,可以避免这种情况。考虑下面的图
  这里写图片描述
  上图造成Dijkstra算法无论怎么修补都得出错误的结论:1-3,1-2。

3. 解决问题

  • A combination of the weighted and unweighted algorithms will solve the problem, but at the cost of a drastic increase in running time. We forget about the concept of known vertices, since our algorithm needs to be able to change its mind.这句看似不重要的话,change its mind。其实直接揭示本质
  • We begin by placing s on a queue. Then, at each stage, we dequeue a vertex v. We find all vertices w adjacent to v such that dw > dv+ cv,w. We update dw and p,w and place w on a queue if it is not already there. A bit can be set for each vertex to indicate presence in the queue. We repeat the process until the queue is empty.
void weighted_negative( TABLE T ){
    QUEUE Q;
    vertex v, w;
    Q = create_queue( NUM_VERTEX ); make_null( Q );
    enqueue( s, Q ); /* BFS策略 */
    while( !is_empty( Q ) ){
        v = dequeue( Q );
        for each w adjacent to v
            if( T[v].dist + cv,w< T[w].dist ){ /*贪婪策略 */
                T[w].dist = T[v].dist + cv,w;
                T[w].path = v;
                if( w is not already in Q )
                    enqueue( w, Q );/*避免重复*/
        }
    }
    dispose_queue( Q );
}

  关键的地方的给出了注释,因为该算法可能改变原来Dijkstra算法中已经标记为know的点(所以引文第一点最后称之为change it’s mind)。对于存在负值圈的情况,该算法也无能为力。再次回顾第二部分的两个图,该算法得出唯一结果1-2-3。

4. 时间复杂度

  • Each vertex can dequeue at most |V| times, so the running time is O ( | E | | V | ) if adjacency lists are used.

  这两点需要动动脑子,上面的算法因为改变了已经出队的点的dv,所以很可能一个点被多次出入队。可以自己画一个图证明该观点,所以时间复杂度为 O ( ( E + V ) V ) = O ( E V ) 。这个时间复杂度为什么这么算要多想想了,上面的计算过程是笔者自己的思路,如果不正确欢迎指正。

猜你喜欢

转载自blog.csdn.net/lovestackover/article/details/80593339