java - 二叉堆 Dijkstra 算法的反例(负权重图)

标签 java algorithm graph dijkstra shortest-path

<分区>

我想知道是否有人可以给出一个对以下代码不起作用的反例(负权重的有向图)(Dijkstra 算法与二叉堆)。我已经尝试了几个例子,但似乎在负边上工作正常,只要我们有更好的方式到达某个节点,它就会更新所有相邻节点的距离。下面是例子

(0) ----2----> (3) -----1-----> (4)
 |              ^
 4              |
 |             -9
 v              |  
(1) ----6----> (2)               

it will print out => 0, 4, 10, 1, 2 

还有

(0) ---1---> (1) ---1---> (2)
 |                         ^
 |                         |
100                      -5000
 |                         |
 \---------> (3) ----------/

this will print => 0, 1, -4900, 100 

下面是Java中的代码

public static void dijkstra(DirectedGraph G, int source) {
    int[] distTo = new int[G.V()];
    Arrays.fill(distTo, Integer.MAX_VALUE);
    distTo[source] = 0;
    PriorityQueue<Node> pq = new PriorityQueue<Node>();
    pq.add(new Node(source, 0));

    while (!pq.isEmpty()) {
        Vertex vertex = pq.poll();
        for (WeightedEdge edge : G.adjTo(vertex.node)) {
            if (edge.weight + distTo[edge.from] < distTo[edge.to]) {
                 distTo[edge.to] = distTo[edge.from] + edge.weight;
                 Vertex adjNode = new Vertex(edge.to, distTo[edge.to]);
                 if (pq.contains(adjNode))
                      pq.remove(adjNode);
                 pq.add(adjNode);
            }
        }
    }
    for (int dist : distTo)
        System.out.print(dist + " ");
}

static class Vertex implements Comparable<Vertex> {
      int node;
      int weight;

      public Vertex(int node, int weight){
             this.node = node;
             this.weight = weight;
      }

      @Override
      public int compareTo(Vertex other) {
             return weight - other.weight;
      }

}

public class DirectedGraph {
       private final int V;
       private int[][]   G;

       public int V() {
              return V;
       }

       public DirectedGraph(int V) {
              this.V = V;
              G = new int[V][V];
       }

       public void addEdge(int v, int w, int weight) {
              G[v][w] = weight;
       }

       public List<WeightedEdge> adjTo(int v) {
              List<WeightedEdge> edges = new LinkedList<WeightedEdge>();
              for (int i = 0; i < V; i++)
                  if (G[v][i] != 0)
                     edges.add(new Edge(v, i, G[v][i]));
              return edges;
       }

}

最佳答案

在 Dijkstra 中,您应该维护一个已访问节点的列表。一旦你扩展了一个节点,你就知道你已经计算出了从根节点到达该节点的最佳方式,并且你不会再次将这个节点插入队列。

这就是 Dijkstra 的本质。如果您不维护该列表,您的代码将陷入负循环的无限循环。您可以使用 Bellman-ford 算法计算单源最短路径并检测是否存在负环路。

关于java - 二叉堆 Dijkstra 算法的反例(负权重图),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30511637/

相关文章:

java - 获取左上角监视器左上角位置的坐标

动态创建图形的 Javascript 库?

找到所选顶点的最小生成树的算法

java - 与初始屏幕共享首选项

java - 如何根据以下字符/单词匹配 URI 字符串的特定部分

algorithm - 动态规划硬币找零问题

c++ - 两次递归调用的递归算法的时间复杂度

algorithm - 在无向图中有负边的地方求一棵最小权生成树

java - 如何禁用或突出显示 JCalendar 中的日期

java - 在树中查找子树的简单方法