赞
踩
图的最短路算法有很多,以下常用的三个算法
算法模板
// 朴素写法 private int s; // 起始点 private int[] dis; // 存储起始点到每个点的最短距离 private boolean[] visited; public Dijkstra(WeightedGraph G, int s) throws Exception { dis = new int[G.V()]; visited = new boolean[G.V()]; Arrays.fill(dis,Integer.MAX_VALUE); dis[0] = 0; while (true){ int curdis = Integer.MAX_VALUE,cur = -1; for (int v = 0; v < G.V();v++){ if (!visited[v] && dis[v] < curdis){ curdis = dis[v]; cur = v; } } if (cur == -1) break; visited[cur] = true; for (int w : G.adj(cur)){ if (!visited[w]){ // G.getWeight(cur,w) 代表cur点到w点的距离 dis[w] = Math.min(dis[cur] + G.getWeight(cur,w) , dis[w]); } } } }
// 堆优化写法 public Dijkstra2(WeightedGraph G, int s) throws Exception { dis = new int[G.V()]; visited = new boolean[G.V()]; Arrays.fill(dis,Integer.MAX_VALUE); pre = new int[G.V()]; Arrays.fill(pre,-1); dis[s] = 0; pre[s] = s; PriorityQueue<Node> pq = new PriorityQueue<>(); pq.add(new Node(s,0)); while (!pq.isEmpty()){ int cur = pq.remove().v; if (visited[cur]) continue; visited[cur] = true; for (int w : G.adj(cur)){ if (!visited[w]){ if (dis[cur] + G.getWeight(cur,w) < dis[w]){ dis[w] = dis[cur] + G.getWeight(cur,w); pq.add(new Node(w,dis[w])); pre[w] = cur; } } } } }
根据三角形定则,一定有 dis[v] < dis[u] + w(假设有边u->v = w)
,否则即存在负边回路。算法模板
public BellmanFord(WeightedGraph G, int s) throws Exception { dis = new int[G.V()]; Arrays.fill(dis,Integer.MAX_VALUE); dis[s] = 0; pre = new int[G.V()]; Arrays.fill(pre,-1); for (int pass = 1; pass < G.V();pass++){ for (int v = 0; v < G.V(); v++){ for (int w : G.adj(v)){ if (dis[v] != Integer.MAX_VALUE && dis[v] + G.getWeight(v,w) < dis[w]){ dis[w] = dis[v] + G.getWeight(v,w); pre[w] = v; } } } } for (int v = 0; v < G.V(); v++){ for (int w : G.adj(v)){ if (dis[v] != Integer.MAX_VALUE && dis[v] + G.getWeight(v,w) < dis[w]){ hasNegativeCycle = true; } } } }
算法模板
private int s; private int[] dist; private boolean[] visit; private Queue<Integer> queue; public int spfa(WeightedGraph G, int s) throws Exception { int n = G.V(); dist = new int[n]; visit = new boolean[n]; Arrays.fill(dist,Integer.MAX_VALUE); queue = new LinkedList<>(); dist[s] = 0; queue.add(s); visit[s] = true; while (!queue.isEmpty()) { int cur = queue.poll(); visit[cur] = false; for (int w : G.adj(cur)) { if (dist[w] > dist[cur] + G.getWeight(cur,w)) { dist[w] = dist[cur] + G.getWeight(cur,w); if (!visit[w]) { queue.add(w); visit[w] = true; } } } } return dist[n-1]; }
d[i][j] = min(d[i][j],d[i][k]+d[k][j])
,而d[i][k]和d[k][j]可以用一样的思想去构建,可以看出这是一个动态规划的思想。在构建i,j中,我们通过枚举所有的k值来进行操作。同样,该算法无法判断负权回路。算法模板
private int[][] dis; private boolean hasNegativeCycle; public Floyed(WeightedGraph G) throws IllegalAccessException { this.G = G; dis = new int[G.V()][G.V()]; for (int i = 0;i < G.V();i++){ Arrays.fill(dis[i],Integer.MAX_VALUE); } // 初始化图 for (int v = 0;v < G.V();v++){ dis[v][v] = 0; for (int w : G.adj(v)){ dis[v][w] = G.getWeight(v,w); } } for (int t = 0; t < G.V();t++){ // 最外层的循环相当于是把所有节点遍历一遍,判断可以从v节点 通过 t节点间接达到 w节点的情况 for (int v = 0; v < G.V();v++){ for (int w = 0; w < G.V();w++){ // 遍历从v节点到w节点可能存在的路径 同时和 从v节点 通过 t节点间接达到 w节点的情况 做比较,得出最短路径的值 if (dis[v][t] != Integer.MAX_VALUE && dis[t][w] != Integer.MAX_VALUE && dis[v][t] + dis[t][w] < dis[v][w]){ dis[v][w] = dis[v][t] + dis[t][w]; } } } } for (int v = 0; v < G.V(); v++){ if (dis[v][v] < 0) hasNegativeCycle = true; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。