本文最后更新于:April 6, 2022 pm
纸上得来终觉浅,绝知此事要躬行。路漫漫其修远兮,吾将上下而求索!知识是经过历史的巨人沉淀下来的,别总想着自己能够快速学会,多花点时间去看看,也许会发现些不同的东西。你能快速学会的、觉得简单的东西,对于别人来说也是一样的。人外有人,天外有天。当努力到达了一定的程度,幸运自会与你不期而遇。
目录 注意:无特殊说明,则n表示点的个数,m表示边的条数。
单源最短路 某一个点到其他点的最短距离。
不存在负边 朴素Dijkstra算法 适合稠密图(点少边多)。常用邻接矩阵存图。时间复杂度:O(n2 )
练习题目:849. Dijkstra求最短路 I
上面的题目已经要收费才能做了,重新给一个其他题目练习。 Dijkstra求最短路
下面实现的代码都是之前的那个题目的AC代码,现在题目不能用了,就仅仅参考吧!思路都是一样的。
邻接矩阵实现 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 100 import java.io.*;import java.math.BigInteger;import java.util.Arrays;import java.util.Scanner;public class Main { public static BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); public static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out)); public static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in))); public static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out)); public static Scanner sc = new Scanner(System.in); public static int maxd = 1000 +7 ; public static int INF = 0x3f3f3f3f ; public static int [] dis = new int [maxd]; public static int [][] g = new int [maxd][maxd]; public static boolean [] vis= new boolean [maxd]; public static long Dijkstra (int n) { for (int i=1 ;i<=n;++i) dis[i] = INF; dis[1 ] = 0 ; for (int i=1 ;i<=n;++i){ int t = -1 ; for (int j=1 ;j<=n;++j){ if ( !vis[j] && ( t==-1 || dis[t]>dis[j] ) ) { t = j; } } vis[t] = true ; for (int j=1 ;j<=n;++j){ dis[j] = Math.min(dis[j],dis[t]+g[t][j]); } } if (dis[n]==INF) return -1 ; else return dis[n]; } public static void main (String[] args) throws Exception { int n = nextInt(); int m = nextInt(); for (int i=1 ;i<=n;++i){ for (int j=1 ;j<=n;++j){ g[i][j] = INF; } } for (int i=1 ;i<=m;++i){ int a = nextInt(); int b = nextInt(); int c = nextInt(); g[a][b]=Math.min(g[a][b],c); } cout.println(Dijkstra(n)); cout.flush(); closeAll(); } public static void cinInit () { cin.wordChars('a' , 'z' ); cin.wordChars('A' , 'Z' ); cin.wordChars(128 + 32 , 255 ); cin.whitespaceChars(0 , ' ' ); cin.commentChar('/' ); cin.quoteChar('"' ); cin.quoteChar('\'' ); cin.parseNumbers(); } public static int nextInt () throws Exception { cin.nextToken(); return (int ) cin.nval; } public static long nextLong () throws Exception { cin.nextToken(); return (long ) cin.nval; } public static double nextDouble () throws Exception { cin.nextToken(); return cin.nval; } public static String nextString () throws Exception { cin.nextToken(); return cin.sval; } public static void closeAll () throws Exception { cout.close(); in.close(); out.close(); } }
链式前向星实现 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 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 import java.io.*;import java.math.BigInteger;import java.util.Arrays;import java.util.Scanner;public class Main { public static BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); public static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out)); public static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in))); public static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out)); public static Scanner sc = new Scanner(System.in); public static int maxd = 100000 +7 ; public static int INF = 0x3f3f3f3f ; public static class Edge { private int pre; private int w; private int to; public void setPre (int pre) { this .pre = pre; } public void setW (int w) { this .w = w; } public void setTo (int to) { this .to = to; } public int getPre () { return pre; } public int getW () { return w; } public int getTo () { return to; } } public static Edge[] edge = new Edge[maxd]; public static int [] head = new int [maxd]; public static int [] dis = new int [maxd]; public static boolean [] vis= new boolean [maxd]; public static int node = 0 ; public static void init (int n,int m) { for (int i=0 ;i<=m;++i) { edge[i] = new Edge(); } for (int i=1 ;i<=n;++i) { head[i]=-1 ; } node=0 ; } public static void add_edge (int a,int b,int c) { edge[node].setTo(b); edge[node].setW(c); edge[node].setPre(head[a]); head[a]=node++; } public static long Dijkstra (int n) { for (int i=1 ;i<=n;++i) dis[i] = INF; dis[1 ] = 0 ; for (int i=1 ;i<=n;++i){ int t = -1 ; for (int j=1 ;j<=n;++j){ if ( !vis[j] && ( t==-1 || dis[t]>dis[j] ) ) { t = j; } } vis[t] = true ; for (int j=head[t];j!=-1 ;j=edge[j].getPre()){ int to = edge[j].getTo(); dis[to]=Math.min(dis[to],dis[t]+edge[j].getW()); } } if (dis[n]==INF) return -1 ; else return dis[n]; } public static void main (String[] args) throws Exception { int n = nextInt(); int m = nextInt(); init(n,m); for (int i=1 ;i<=m;++i){ int a = nextInt(); int b = nextInt(); int c = nextInt(); add_edge(a,b,c); } cout.println(Dijkstra(n)); cout.flush(); closeAll(); } public static void cinInit () { cin.wordChars('a' , 'z' ); cin.wordChars('A' , 'Z' ); cin.wordChars(128 + 32 , 255 ); cin.whitespaceChars(0 , ' ' ); cin.commentChar('/' ); cin.quoteChar('"' ); cin.quoteChar('\'' ); cin.parseNumbers(); } public static int nextInt () throws Exception { cin.nextToken(); return (int ) cin.nval; } public static long nextLong () throws Exception { cin.nextToken(); return (long ) cin.nval; } public static double nextDouble () throws Exception { cin.nextToken(); return cin.nval; } public static String nextString () throws Exception { cin.nextToken(); return cin.sval; } public static void closeAll () throws Exception { cout.close(); in.close(); out.close(); } }
堆优化Dijkstra算法 适合稀疏图(点多边少)。时间复杂度:O(m*logn )
练习题目:850. Dijkstra求最短路 II 。同样,重新再给一个练习题目 Dijkstra求最短路
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 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 import java.io.*;import java.math.BigInteger;import java.util.*;public class Main { public static BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); public static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out)); public static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in))); public static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out)); public static Scanner sc = new Scanner(System.in); public static int maxd = 200000 +7 ; public static int INF = 0x3f3f3f3f ; public static int [] head = new int [maxd]; public static int [] edgePre = new int [maxd]; public static int [] edgeW = new int [maxd]; public static int [] edgeTo = new int [maxd]; public static int [] dis = new int [maxd]; public static boolean [] vis= new boolean [maxd]; public static int node = 0 ; public static class Edge implements Comparable <Edge > { private int to; private int w; Edge(int to, int w) { this .to = to; this .w = w; } public int compareTo (Edge obj) { return this .w - obj.w; } } public static void init (int n,int m) { for (int i=1 ;i<=n;++i) { head[i]=-1 ; dis[i]=INF; vis[i]=false ; } node=0 ; } public static void add_edge (int a,int b,int c) { edgeTo[node]=b; edgeW[node]=c; edgePre[node]=head[a]; head[a]=node++; } public static void Dijkstra (int start,int end) { PriorityQueue<Edge> q = new PriorityQueue<Edge>(); q.add(new Edge(start,0 )); dis[start] = 0 ; while (!q.isEmpty()) { int u = q.poll().to; if (vis[u] == true ) continue ; vis[u] = true ; for (int i = head[u]; i!=-1 ; i=edgePre[i]) { int to = edgeTo[i]; if (dis[to] > dis[u] + edgeW[i]) { dis[to] = dis[u] + edgeW[i]; q.add(new Edge(to, dis[to])); } } } } public static void main (String[] args) throws Exception { int n = nextInt(); int m = nextInt(); init(n,m); for (int i=1 ;i<=m;++i){ int a = nextInt(); int b = nextInt(); int c = nextInt(); add_edge(a,b,c); } Dijkstra(1 ,n); cout.println(dis[n]==INF? -1 :dis[n]); cout.flush(); closeAll(); } public static void cinInit () { cin.wordChars('a' , 'z' ); cin.wordChars('A' , 'Z' ); cin.wordChars(128 + 32 , 255 ); cin.whitespaceChars(0 , ' ' ); cin.commentChar('/' ); cin.quoteChar('"' ); cin.quoteChar('\'' ); cin.parseNumbers(); } public static int nextInt () throws Exception { cin.nextToken(); return (int ) cin.nval; } public static long nextLong () throws Exception { cin.nextToken(); return (long ) cin.nval; } public static double nextDouble () throws Exception { cin.nextToken(); return cin.nval; } public static String nextString () throws Exception { cin.nextToken(); return cin.sval; } public static void closeAll () throws Exception { cout.close(); in.close(); out.close(); } }
存在负边 SPFA 可以判断是否存在环。时间复杂度:O(m)(一般情况),最坏情况O(n*m)。不论边权是正的还是负的,都可以做。算法平均时间复杂度是 O(km),k 是常数。
添加一个练习题目 可参考下面代码。
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 public static int maxd = 100000 +7 ;public static int INF = 0x3f3f3f3f ;public static int [] dis = new int [maxd];public static int [] head = new int [maxd];public static int [] edgePre = new int [maxd]; public static int [] edgeW = new int [maxd]; public static int [] edgeTo = new int [maxd]; public static int [] num = new int [maxd]; public static boolean [] vis = new boolean [maxd];public static int node = 0 ;public static void init (int n,int m) { for (int i=1 ;i<=n;++i) { head[i]=-1 ; dis[i]=INF; vis[i]=false ; } node=0 ; }public static void add_edge (int a,int b,int c) { edgeTo[node]=b; edgeW[node]=c; edgePre[node]=head[a]; head[a]=node++; }public static boolean SPFA (int end) { Queue<Integer> q = new LinkedList<Integer>(); q.add(1 ); dis[1 ]=0 ; num[1 ]=1 ; vis[1 ]=true ; while (!q.isEmpty()){ int u = q.poll(); vis[u]=false ; for (int i = head[u];i!=-1 ;i=edgePre[i]){ int v = edgeTo[i]; if (dis[v]<=dis[u]+edgeW[i]) continue ; dis[v]=dis[u]+edgeW[i]; num[v]=num[u]+1 ; if (num[v]>end){ return true ; } if (!vis[v]){ vis[v] = true ; q.add(v); } } } return false ; }
多源最短路 Floyd 可以求任意两点间的最短距离。时间复杂度:O(n3 )。一种动态规划算法,稠密图效果最佳,边权可正可负。
练习题目:849. Dijkstra求最短路 I 。重新添加一个题目 Dijkstra求最短路
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 import java.io.*;import java.text.SimpleDateFormat;import java.util.*;public class Main { public static BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); public static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out)); public static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in))); public static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out)); public static Scanner sc = new Scanner(System.in); public static int maxd = 1000 +7 ; public static int INF = 0x3f3f3f3f ; public static int [][] dp = new int [maxd][maxd]; public static void floyd (int n) { for (int k=1 ;k<=n;++k){ for (int i=1 ;i<=n;++i){ for (int j=1 ;j<=n;++j){ if (dp[i][j]>dp[i][k]+dp[k][j]){ dp[i][j]=dp[i][k]+dp[k][j]; } } } } } public static void main (String[] args) throws Exception { int n = nextInt(); int m = nextInt(); for (int i=1 ;i<=n;++i){ for (int j=1 ;j<=n;++j){ dp[i][j]=INF; } } while (m-->0 ){ int a = nextInt(); int b = nextInt(); int c = nextInt(); dp[a][b] = Math.min(dp[a][b],c); } floyd(n); cout.println(dp[1 ][n]==INF? -1 :dp[1 ][n]); cout.flush(); closeAll(); } public static void cinInit () { cin.wordChars('a' , 'z' ); cin.wordChars('A' , 'Z' ); cin.wordChars(128 + 32 , 255 ); cin.whitespaceChars(0 , ' ' ); cin.commentChar('/' ); cin.quoteChar('"' ); cin.quoteChar('\'' ); cin.parseNumbers(); } public static int nextInt () throws Exception { cin.nextToken(); return (int ) cin.nval; } public static long nextLong () throws Exception { cin.nextToken(); return (long ) cin.nval; } public static double nextDouble () throws Exception { cin.nextToken(); return cin.nval; } public static String nextString () throws Exception { cin.nextToken(); return cin.sval; } public static void closeAll () throws Exception { cout.close(); in.close(); out.close(); } }