使用二进制堆实现Dijkstra算法

时间:2017-12-02 22:08:22

标签: java algorithm heap dijkstra binary-heap

你将如何使用二进制堆来实现Dijkstra的算法?我的目标是运行O(M log N)。

假设一个王国中有N个城市,这个王国有M个火车路线,S是首都。

输入是N M S,接着是M分离三联体(U,V和D)的列表,这意味着从U市到V市的列车路线需要D天。请注意,此列车路线只能从城市U到V,而不是从V到U.

输出是一行,包含一个以空格分隔的N个整数列表,其中第I个整数是从城市I到城市S的最小天数。如果从城市I到城市旅行是不可能的S,输出 - 1为第I个整数。

如果样本输入是这样的:

 4 4 4
 1 4 1
 3 1 2
 3 4 4
 4 2 1

然后输出是:

 1 -1 3 0

这是另一个例子:

 5 8 2
 3 2 2
 2 3 2
 2 5 2
 5 2 2
 4 2 2
 2 4 2
 1 4 2
 2 1 2

输出结果为:

 4 0 2 2 2

我的目标是尝试使用二进制堆来解决这个问题,但我遇到了麻烦。我现在正在使用邻接列表,我会看看是否可以在此发布代码,但如果你可以帮助我,那将会非常有用。

感谢您的帮助。

编辑:这是我使用邻接列表的代码。

//import static jdk.nashorn.internal.runtime.regexp.joni.Syntax.Java;

import java.util.Scanner;

公共课Dijkstra {   public static void main(String [] args){

int N, M, S;

Scanner scan = new Scanner(System.in);
N = scan.nextInt(); // # cities
M = scan.nextInt(); // # train routes
S = scan.nextInt(); // capital city
// System.out.println(N + " " + M + " " + S);


// NOW THE ARRAYS
int [][] A = new int[50010][60]; // the neighbors of each city
int [][] W = new int[50010][60]; // the weights of going to neighbors
int []   deg = new int[50010]; // the degree of the city
// The limits are 50,010 and 60 because the problem statement said that there are at most
// 50,000 cities, and we just added 10 just to be sure. We have 60 because the maximum number of
// train routes is 50, and we just added 10 to that.

// with each incoming vertex/city, we will at first initialize the degree to be 0
for(int i = 1; i <=N; ++i) {
  deg[i] = 0;  // initialize the degree of each vertex to 0
}

// this is for each of the train routes
for(int i = 1; i <= M; ++i) {
  int u, v, w;
  u = scan.nextInt(); // origin
  v = scan.nextInt(); // destination
  w = scan.nextInt(); // # days
  // System.out.println(u + " " + v + " " + w);

  // WITH THE ARRAYS
  A[u][deg[u]] = v; // adding an edge (u,v) to the graph where u is origin and deg[u] is weight
  W[u][deg[u]] = w; // set its weight to w, the number of days it takes
  deg[u]++; // increase degree of vertex u by 1
}

//for(int i = 1; i <= N; ++i) {
//  System.out.println("vertex:" + i + "'s neighbors");
//  for(int j = 0; j < deg[i]; ++j) {
//    System.out.println(A[i][j] + " " + W[i][j]);
//  }
//}




// compute distance from U (origin) to S (capital city) by Dijkstra's algorithm
// Dijkstra's algorithm: find the shortest path distance from each vertex to the capital
for(int U = 1; U <= N; ++U) {

  // INITIALIZATION
  int[] visited = new int[50010]; // create an empty array w/ max # cities space for cities that are visited
  int[] dist = new int[50010]; // create an empty array w/ max # cities space for distance of each city
  // loop that goes through the arrays and fills in values up to N number of cities
  for(int V = 1; V <= N; ++V) {
    dist[V] = 100000000; // set the distance of the city to the capital to be the maximum possible number
    visited[V] = 0; // set the cities that are visited to be 0
  }

  // ACTUAL ALGORITHM
  dist[U] = 0; // set the distance of the city to be 0

  for(int k = 1; k <= N; ++k) {
    //find an unvisited vertex with minimum distance
    int min = 100000000;
    int minVertex = 1;

    for(int i = 1; i<=N; ++i) {
      // if the city has not been visited and the distance from it to the capital is less than the minimum
      if(visited[i] == 0 && dist[i] < min) {
        min = dist[i]; // set the new minimum to be this distance
        minVertex = i; // set the minimum vertex to be this number
      }
    }

    visited[minVertex] = 1; // set this value to 1 to show that the city has been visited

    // relax the edges that are adjacent to minVertex to update the shortest path distance to
    // neighbors of minVertex
    for(int j = 0; j < deg[minVertex]; ++j) { // this is updating the minimum weight of the city
      // A[minVertex][j] is the j-th neighbor of minVertex
      // W[minVertex][j] is the weight of the corresponding edge
      int newDist = dist[minVertex] + W[minVertex][j];
      if (newDist < dist[A[minVertex][j]]) {
        dist[A[minVertex][j]] = newDist;
      }
    }
  }

  if(dist[S] == 100000000) { // if the distance of this city is still the maximum, it does not have a connection
    System.out.print("-1 ");
  }
  else { // if it has a distance less than max, it means there is a minimum distance and we will print that
    System.out.print(dist[S] + " ");
  }

}

System.out.println("");

}

}

1 个答案:

答案 0 :(得分:0)

要获得时间复杂度,您需要使用使用堆的次优先级队列(这不是完全排序的结构)。有关更多信息,请here

使用堆的想法是你将任何节点的所有成功者放在priotity队列中,这是在堆的帮助下实现的,并且删除了具有最小队列成本的节点。因为Heap结构没有完全排序,并且在堆/队列中插入节点是~logN,您还可以获得有关此here的更多信息