无向图中,权值>=0,找出从节点s到t的最短距离: 令d[i]为从s到i的最短距离,则从s到i的最短路径不会再变更,以后再更新d,d[i]也不会改变,那么与i相邻的其它节点的最短距离也就随之确定: d[j] = min(d[j], d[i] + (从i到j的权值)),j = 1,2,3…. 更新完与i相邻的节点j后,d[j]也就固定下来了,再从d[j]中选取一个 距离最小的 && 还未固定下来 的节点,直到所有节点的距离都固定下来为止。 这就是Dijkstra算法。
1 2 3 4 5 6 7 8 9 10 11 while (true ){ int u = -1 ; for ( int i from 0 to N-1 ){ if (!visited[i] && (u == -1 || d[i] < d[u])) u = i; } if (u == -1 )break ; visited[u] = true ; for ( int i from 0 to N-1 ){ d[i] = min(d[i], d[u] + weight[u][i]); } }
一共有N次循环,N为节点个数,每次循环的代价是 2*N,所以Dijkstra的时间复杂度为O(N^2).
使用优先队列对其进行优化,将待固定节点i和d[i]封装成元素E(i, d[i])放入队列中,以d[i]升序排列,则每次取队首的代价是O(1),因为要循环N次,所以是从队列中取N次的总代价是O(lgN),总代价成了O(NlgN)。 这是使用邻接矩阵的优化时间复杂度,如果边数M比N小,换成邻接表,那么取出队首元素后遍历该元素的边,边数最多为M,那么时间复杂度就是O(MlgN)。
如果是稀疏图,就用邻接表,否则就用邻接矩阵。
hdu1874 AC code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 import java.io.*;import java.util.PriorityQueue;public class Main implements Runnable { public void solve () { int MAX_DIST = 1 << 24 ; int N, M; while ((N = nextInt()) != -1 ) { M = nextInt(); int [][] weight = new int [N][N]; int [] dist = new int [N]; boolean [] visited = new boolean [N]; for (int i = 0 ; i < N; i++) { dist[i] = MAX_DIST; visited[i] = false ; for (int j = 0 ; j <= i; j++) weight[i][j] = weight[j][i] = MAX_DIST; } for (int i = 0 ; i < M; i++) { int u = nextInt(), v = nextInt(), w = nextInt(); if (w < weight[u][v]) weight[u][v] = weight[v][u] = w; } int start = nextInt(), end = nextInt(); dist[start] = 0 ; PriorityQueue<Edge> que = new PriorityQueue <>(); que.add(new Edge (start, 0 )); while (!que.isEmpty()) { Edge e = que.poll(); if (!visited[e.v]) { visited[e.v] = true ; for (int i = 0 ; i < N; i++) { if (!visited[i]) { int w = dist[e.v] + weight[e.v][i]; if (w < dist[i]) { dist[i] = w; que.add(new Edge (i, dist[i])); } } } } } if (dist[end] < MAX_DIST) { out.println(dist[end]); } else { out.println(-1 ); } } } static class Edge implements Comparable <Edge> { int v, w; public Edge (int v, int w) { this .v = v; this .w = w; } @Override public int compareTo (Edge o) { return this .w - o.w; } } public static void main (String[] args) { new Main ().run(); } @Override public void run () { init(); solve(); out.flush(); } StreamTokenizer in; PrintWriter out; public void init () { in = new StreamTokenizer (new BufferedReader (new InputStreamReader (System.in))); out = new PrintWriter (new OutputStreamWriter (System.out)); } public int nextInt () { try { if (in.nextToken() == StreamTokenizer.TT_EOF) return -1 ; else return (int ) in.nval; } catch (IOException e) { throw new Error (e); } } }
java 读到文件末 in.nextToken() == StreamTokenizer.TT_EOF 只能这样判断,如果没有判断,返回的 in.nval 并不是-1,所以程序不会停止。