【java】最短路径算法
2017-05-09 18:41
369 查看
Dijkstra算法
Dijkstra算法可用于求正权图上的单源最短路径,该算法适用于有向图和无向图。如果要求每两点之间的最短路径,需要调用n次Dijkstra算法,或者使用Floyd算法。该算法的伪代码:
清除所有点的标号 设d[0]=0,其他d[i]=INF 循环n次 { 在所有未标号节点中,选出d值最小的节点x 给结点x标记 对于从x出发的所有边(x,y),更新d[y]=min{d[y],d[x]+w[x,y]} }
更新d[y]的过程又称为松弛操作,即对迄今为止找到的v的最短路径进行改进。
先输入结点数目n,边的数目m,之后输入m行数据,每行代表一条边的起点,终点,权值,最后输入开始结点的编号,最后输出从开始结点到其余各点的最短路径。
样例输入:
7 11
0 1 7
0 3 5
1 2 8
1 3 9
1 4 7
2 4 5
3 4 15
3 5 6
4 5 8
4 6 9
5 6 11
0
样例输出:
0 7 15 5 14 11 22
import java.util.Arrays; import java.util.Scanner; public class Main { public static void main(String[] args){ Scanner scanner = new Scanner(System.in); while(scanner.hasNext()){ int n=scanner.nextInt(); int m=scanner.nextInt(); int[][] edges=new int ; for(int i=0;i<m;i++){ int u=scanner.nextInt(); int v=scanner.nextInt(); int weight=scanner.nextInt(); edges[u][v]=weight; edges[v][u]=weight; } int src=scanner.nextInt(); int[] dist=new int ; //存放源点到各点的最短路径长度,d[src]=0 Arrays.fill(dist, Integer.MAX_VALUE); dist[src]=0; int[] visited=new int ; for(int i=0;i<n;i++){ //循环n次,每次可以得到源点src到一个点的最短路径 int x=-1,min=Integer.MAX_VALUE; for(int j=0;j<n;j++){ //选出未访问的结点中dist最小的结点 if(visited[j]==0&&dist[j]<min){ x=j; min=dist[j]; } } visited[x]=1; for(int k=0;k<n;k++){ //更新dist值,松弛操作 if(edges[x][k]>0){ int temp=dist[x]+edges[x][k]; if(dist[k]>temp) dist[k]=temp; } } } StringBuffer str=new StringBuffer(); for(int i:dist) str.append(i+" "); System.out.print(str.substring(0,str.length()-1)); } scanner.close(); } }
对于以上算法的优化,可分两个部分:
①更新dist[]值,以上算法使用邻接矩阵存储图,这样,每次更新dist都需要循环n次,当我们改用邻接表存储边时,可减少循环次数。
②查找dist[]中最小的值,以上算法每次都需要循环n次,我们可以使用优先队列实现这一过程,在优先队列中,元素并不是按照进入队列的先后顺序排列,而是按照优先级的高低顺序排列。Java的优先队列每次取最小元素,C++的优先队列每次取最大元素。
import java.util.Arrays; import java.util.Comparator; import java.util.PriorityQueue; import java.util.Scanner; class MyComparator implements Comparator<Pair>{ public int compare(Pair p1, Pair p2) { if(p1.dist>p2.dist) return 1; else if(p1.dist<p2.dist) return -1; return 0; } } class Pair{ int index; int dist; Pair(int index,int dist){ this.index=index; this.dist=dist; } } public class Main { public static void main(String[] args){ Scanner scanner = new Scanner(System.in); while(scanner.hasNext()){ int n=scanner.nextInt(); int m=scanner.nextInt(); int[][] edges=new int ; for(int i=0;i<m;i++){ int u=scanner.nextInt(); int v=scanner.nextInt(); int weight=scanner.nextInt(); edges[u][v]=weight; edges[v][u]=weight; } int src=scanner.nextInt(); int[] dist=new int ; //存放源结点到其余结点的最短路径长度,dist[src]=0,其余为INF Arrays.fill(dist, Integer.MAX_VALUE); dist[src]=0; PriorityQueue<Pair> queue=new PriorityQueue<>(new MyComparator()); queue.offer(new Pair(src,0)); int[] fa=new int ; //存放最短路径中到该节点的上一个节点,fa[src]=src,如不需要输出路径可省略 fa[src]=src; Arrays.fill(fa, -1); int[] visited=new int ; while(!queue.isEmpty()){ Pair pair=queue.poll(); int index=pair.index; visited[index]=1; for(int i=0;i<n;i++){ if(visited[i]==0&&edges[index][i]>0){ int temp=pair.dist+edges[index][i]; if(dist[i]>temp){ dist[i]=temp; fa[i]=index; queue.offer(new Pair(i,dist[i]));//减少了冗余的松弛操作 } } } } StringBuffer str=new StringBuffer(); for(int i:dist) str.append(i+" "); System.out.print(str.substring(0,str.length()-1)); } scanner.close(); } }以上算法中,优先队列PriorityQueue的存储情况:
①(0,0)
②(1,7) (3,5)
③(1,7) (4,20) (5,11)
④(4,20) (5,11) (2,15) (4,14)
省略......
可以看出一个结点会进入队列多次,而优先队列只是选出最小的那个而已。在java中,优先队列Prior
4000
ityQueue是用小顶堆实现的。
Floyd算法
Floyd算法是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法。分析:从结点i到结点j的最短距离,要么是从i直接到j,要么是从结点i,经过某些中转结点k,最后到结点j。
设dist(i,j)表示结点i到结点j的最短距离,则其状态转移方程是:dist[i,j]:=min{dist[i,k]+dist[k,j],dist[i,j]}。
先输入结点数目n,边的数目m,之后输入m行数据,每行代表一条边的起点,终点,权值,最后输出所有结点到其余各点的最短路径长度。
样例输入:
7 11
0 1 7
0 3 5
1 2 8
1 3 9
1 4 7
2 4 5
3 4 15
3 5 6
4 5 8
4 6 9
5 6 11
样例输出:
0 7 15 5 14 11 22
7 0 8 9 7 15 16
15 8 0 17 5 13 14
5 9 17 0 14 6 17
14 7 5 14 0 8 9
11 15 13 6 8 0 11
22 16 14 17 9 11 0
import java.util.Scanner; public class Main { public static void main(String[] args){ Scanner scanner = new Scanner(System.in); while(scanner.hasNext()){ int n=scanner.nextInt(); int m=scanner.nextInt(); int[][] edges=new int ; for(int i=0;i<m;i++){ int u=scanner.nextInt(); int v=scanner.nextInt(); int weight=scanner.nextInt(); edges[u][v]=weight; edges[v][u]=weight; } int[][] dist=new int ; //dist[i][j]存放结点i到结点j的最短路径大小 for(int i=0;i<n;i++) for(int j=0;j<n;j++){ if(i==j) dist[i][j]=0; else dist[i][j]=edges[i][j]==0?Integer.MAX_VALUE:edges[i][j]; } for(int k=0;k<n;k++) for(int i=0;i<n;i++) for(int j=0;j<n;j++){ if(dist[i][k]<Integer.MAX_VALUE&&dist[k][j]<Integer.MAX_VALUE &&dist[i][j]>dist[i][k]+dist[k][j]) dist[i][j]=dist[i][k]+dist[k][j]; } for(int i=0;i<n;i++){ StringBuffer str=new StringBuffer(); for(int j=0;j<n;j++) str.append(dist[i][j]+" "); System.out.println(str.substring(0,str.length()-1)); } } scanner.close(); } }
相关文章推荐
- 算法java实现--贪心算法--单源最短路径问题--Dijkstra算法
- 算法——数据结构图的最短路径实现JAVA代码
- java实现图的最短路径(SP)的迪杰斯特拉(Dijkstra)算法
- 去哪网笔试 最短路径算法(词梯) Java实现
- Java邻接表表示加权有向图,附dijkstra最短路径算法
- 用java编写的一个迪杰斯特拉算法(单源最短路径算法,Dijkstra算法)。
- 最短路径算法之Dijkstra算法_Java实现
- 图论最短路径算法-Dijkstra算法-单源最短路径-JAVA语言描述
- java实现图的最短路径(SP)的贝尔曼福特(Bellman-Ford)算法
- java实现城市间最短路径算法
- 最短路径顶点算法:最短路径之迪杰斯特拉(Dijkstra)算法Strut2教程-java教程
- A*Star 最短路径算法的Java实现
- 最短路径算法之Dijkstra算法(java实现)
- 无向图的最短路径算法JAVA实现(转)
- 用java编写的一个迪杰斯特拉算法(单源最短路径算法,Dijkstra算法)。
- 算法java实现--分支限界法--单源最短路径问题
- 最短路径A*算法原理及java代码实现(看不懂是我的失败)
- 最短路径算法之Dijkstra算法(java实现)
- 图论最短路径算法-Floyd算法-JAVA代码实现
- 基于java最短路径算法公交查询系统的设计与实现