使用二叉堆实现 Dijkstra 算法
Posted
技术标签:
【中文标题】使用二叉堆实现 Dijkstra 算法【英文标题】:Implementing Dijkstra's algorithm using Binary Heaps 【发布时间】:2018-05-16 17:21:34 【问题描述】:您将如何使用二进制堆实现 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,第I个整数输出 - 1。
如果样本输入是这样的:
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;
导入 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("");
【问题讨论】:
作为本网站的一般规则,您应该在问题中发布一些代码,向我们展示您已经尝试过的内容。 你没有说你的程序应该找到什么。 @ubadub 对不起,我是这个网站的新手。我发布了上面的代码 @MattTimmermans 我应该输出一行,其中包含以空格分隔的 N 个整数列表,其中第 I 个整数是从城市 I 到城市 S(首都城市)。如果无法从城市 I 到城市 S,则输出第 I 个整数 -1。 倒转火车路线,计算从 S 到 all I 所需的时间。 【参考方案1】:要获得这种时间复杂度,您需要使用利用堆的次优先级队列(它不是完全排序的结构)。更多信息请看here。
使用堆的想法是,您将任何节点的所有后继者放入优先队列中,这是在堆的帮助下实现的,并从队列中删除成本最低的节点。因为堆结构没有完全排序并且在堆/队列中插入一个节点是~logN
,你也可以得到更多关于这个here的信息
【讨论】:
以上是关于使用二叉堆实现 Dijkstra 算法的主要内容,如果未能解决你的问题,请参考以下文章
P4779 模板单源最短路径(标准版)二叉堆优化的 Dijkstra