最短路问题——Java语言实现
最短路
最短路问题分为俩个模块,单源最短路和多源最短路问题,而单源最短路中又分为4种算法,分别总结一下
单源最短路问题
单源最短路问题(又称为SSSP问题),给定一张有向图,n个点,m个边,节点以[1,n]之间的连续整数编号,(x,y,z)描述一条从x出发,到达y,长度为z的有向边。设1号点为起点,求长度为n的数组dist,其中dist[i]表示从起点1到节点i的最短路径的长度
Dijkstra算法
算法的基本流程:
- 初始化dist[1] = 0,其余节点都为正无穷大
- 找到应该未标记的,dist[x]最小节点x,然后标记节点x
- 扫描节点x的所有出边(x,y,z),若dist[y]>distp[x]+z,则使用dist[x]+z更新dist[y]
- 重复上述2-3,直到所有节点都被标记
不难发现,基于贪心,故只适用于边的长度为非负
当边长都为非负数的时候,全局最小值已经不能被其他节点更新,故在第一步中选出的节点x必然满足:dist[x]已经是起点到x的最短路径,进行不断的选择,标记,拓展,最终得到每个节点的最短路径的长度
package 最短路;public class Dijkstra {/** 参数adjMatrix:为图的权重矩阵,权值为-1的两个顶点表示不能直接相连* 函数功能:返回顶点0到其它所有顶点的最短距离,其中顶点0到顶点0的最短距离为0*/public int[] getShortestPaths(int[][] adjMatrix) {int[] result = new int[adjMatrix.length]; //用于存放顶点0到其它顶点的最短距离boolean[] used = new boolean[adjMatrix.length]; //用于判断顶点是否被遍历used[0] = true; //表示顶点0已被遍历for(int i = 1;i < adjMatrix.length;i++) {result[i] = adjMatrix[0][i];used[i] = false;}for(int i = 1;i < adjMatrix.length;i++) {int min = Integer.MAX_VALUE; //用于暂时存放顶点0到i的最短距离,初始化为Integer型最大值int k = 0;for(int j = 1;j < adjMatrix.length;j++) { //找到顶点0到其它顶点中距离最小的一个顶点if(!used[j] && result[j] != -1 && min > result[j]) {min = result[j];k = j;}}used[k] = true; //将距离最小的顶点,记为已遍历for(int j = 1;j < adjMatrix.length;j++) { //然后,将顶点0到其它顶点的距离与加入中间顶点k之后的距离进行比较,更新最短距离if(!used[j]) { //当顶点j未被遍历时//首先,顶点k到顶点j要能通行;这时,当顶点0到顶点j的距离大于顶点0到k再到j的距离或者顶点0无法直接到达顶点j时,更新顶点0到顶点j的最短距离if(adjMatrix[k][j] != -1 && (result[j] > min + adjMatrix[k][j] || result[j] == -1))result[j] = min + adjMatrix[k][j];}}}return result;}public static void main(String[] args) {Dijkstra test = new Dijkstra();int[][] adjMatrix = {{0,6,3,-1,-1,-1},{6,0,2,5,-1,-1},{3,2,0,3,4,-1},{-1,5,3,0,2,3},{-1,-1,4,2,0,5},{-1,-1,-1,3,5,0}};int[] result = test.getShortestPaths(adjMatrix);System.out.println("顶点0到图中所有顶点之间的最短距离为:");for(int i = 0;i < result.length;i++)System.out.print(result[i]+" ");}
}
存在负权边,Bellman-Ford
基于迭代思想:
- 扫描所有边(x,y,z),若dist[y]>dist[x]+z,则用dist[x]+z更新dist[y]
- 重复上面的步骤,直到没有更新操作发生
package 最短路;import java.util.Scanner;public class BellmanFord {public long[] result; //用于存放第0个顶点到其它顶点之间的最短距离//内部类,表示图的一条加权边class edge {public int a; //边的起点public int b; //边的终点public int value; //边的权值edge(int a, int b, int value) {this.a = a;this.b = b;this.value = value;}}//返回第0个顶点到其它所有顶点之间的最短距离public boolean getShortestPaths(int n, edge[] A) {result = new long[n];for (int i = 1; i < n; i++)result[i] = Integer.MAX_VALUE; //初始化第0个顶点到其它顶点之间的距离为无穷大,此处用Integer型最大值表示for (int i = 1; i < n; i++) {for (int j = 0; j < A.length; j++) {if (result[A[j].b] > result[A[j].a] + A[j].value)result[A[j].b] = result[A[j].a] + A[j].value;}}boolean judge = true;for (int i = 1; i < n; i++) { //判断给定图中是否存在负环if (result[A[i].b] > result[A[i].a] + A[i].value) {judge = false;break;}}return judge;}public static void main(String[] args) {BellmanFord test = new BellmanFord();Scanner in = new Scanner(System.in);System.out.println("请输入一个图的顶点总数n和边总数p:");int n = in.nextInt();int p = in.nextInt();edge[] A = new edge[p];System.out.println("请输入具体边的数据:");for (int i = 0; i < p; i++) {int a = in.nextInt();int b = in.nextInt();int value = in.nextInt();A[i] = test.new edge(a, b, value);}if (test.getShortestPaths(n, A)) {for (int i = 0; i < test.result.length; i++)System.out.print(test.result[i] + " ");} elseSystem.out.println("给定图存在负环,没有最短距离");}}
存在负权边,SPFA
实际上,SPFA算法在国际上统称为“队列优化的Bellman-Ford算法,仅在中国称为”SPFA“算法
流程如下:
- 建立一个队列,起初队列中只含有起点1
- 取出队头节点x,扫描它的所有出边(x,y,z)若,dist[y]>dist[x]+z,则使用dist[x]+z更新dist[y]。同时,若y不在队列中,则把y入队
- 重复,直到队列为空
package 最短路;import java.util.ArrayList;
import java.util.Scanner;public class SPFA {public long[] result; //用于得到第s个顶点到其它顶点之间的最短距离//内部类,用于存放图的具体边数据class edge {public int a; //边的起点public int b; //边的终点public int value; //边的权值edge(int a, int b, int value) {this.a = a;this.b = b;this.value = value;}}/** 参数n:给定图的顶点个数* 参数s:求取第s个顶点到其它所有顶点之间的最短距离* 参数edge:给定图的具体边* 函数功能:如果给定图不含负权回路,则可以得到最终结果,如果含有负权回路,则不能得到最终结果*/public boolean getShortestPaths(int n, int s, edge[] A) {ArrayList<Integer> list = new ArrayList<Integer>();result = new long[n];boolean[] used = new boolean[n];int[] num = new int[n];for(int i = 0;i < n;i++) {result[i] = Integer.MAX_VALUE;used[i] = false;}result[s] = 0; //第s个顶点到自身距离为0used[s] = true; //表示第s个顶点进入数组队num[s] = 1; //表示第s个顶点已被遍历一次list.add(s); //第s个顶点入队while(list.size() != 0) {int a = list.get(0); //获取数组队中第一个元素list.remove(0); //删除数组队中第一个元素for(int i = 0;i < A.length;i++) {//当list数组队的第一个元素等于边A[i]的起点时if(a == A[i].a && result[A[i].b] > result[A[i].a] + A[i].value) {result[A[i].b] = result[A[i].a] + A[i].value;if(!used[A[i].b]) {list.add(A[i].b);num[A[i].b]++;if(num[A[i].b] > n)return false;used[A[i].b] = true; //表示边A[i]的终点b已进入数组队}}}used[a] = false; //顶点a出数组对}return true;}public static void main(String[] args) {SPFA test = new SPFA();Scanner in = new Scanner(System.in);System.out.println("请输入一个图的顶点总数n起点下标s和边总数p:");int n = in.nextInt();int s = in.nextInt();int p = in.nextInt();edge[] A = new edge[p];System.out.println("请输入具体边的数据:");for(int i = 0;i < p;i++) {int a = in.nextInt();int b = in.nextInt();int value = in.nextInt();A[i] = test.new edge(a, b, value);}if(test.getShortestPaths(n, s, A)) {for(int i = 0;i < test.result.length;i++)System.out.print(test.result[i]+" ");} elseSystem.out.println("给定图存在负环,没有最短距离");}
}
最短路问题——Java语言实现相关推荐
- Java语言中的数据类型
Java语言是一种强调数据类型的语言,在声明任何变量时,必须将该变量定义为一种数据类型. Java中的数据类型包括基本类型和对象类型,基本类型总共有8种,其中4种整形.1种字符型.2种浮点型.1种布尔 ...
- java语言环境变量_JAVA语言环境变量的设置教程
本文主要向大家介绍了JAVA语言环境变量的设置教程,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助. 安装JDK到目录,我这里是C:\Java 右键点击计算机属性 在系统变量里面建 JA ...
- java语言的实现机制_JAVA语言之Java NIO的工作机制和实现原理介绍
本文主要向大家介绍了JAVA语言之Java NIO的工作机制和实现原理介绍,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助. 前言 本文只简单介绍NIO的原理实现和基本工作流程 I/O和 ...
- Java语言的基础知识9
第十一章(线程) 1.通过String name=Thread.currentThread().getName();来获取当前线程的名称. 2.多次启动一个线程或者启动一个已经运行的线程是非法的,会抛 ...
- 重塑云上的 Java 语言
点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 Photo @ Toa Heftiba 文 |郁磊 音乐无国界, ...
- 四川大学java试题_四川大学2013年计算机(软件)学院Java语言程序设计期末考试试题B卷...
四川大学期末考试试题(闭卷) (2013 -2014学年第1学期) 课程号:课程名称: Java语言程序设计(B 卷)任课教师: 适用专业年级:学号:姓名: 一.单项选择题(本大题共20小题,每小题2 ...
- “坑爹”排行榜:Java语言最违反常识的功能点TOP 10
来自:互联网全栈架构 作为一门面向对象的编程语言,Java凭借其简单易用.功能强大的特点受到了广大编程爱好者的青睐,伴随着开源社区的推波助澜,Java语言更是席卷全球,势不可挡,在世界各地都有Java ...
- Java语言中的生僻知识
最近有一首名叫<生僻字>的流行歌曲火遍大江南北,创作者给佶屈聱牙的生僻字,配上了优美明快的旋律,竟然让歌曲变得琅琅上口.悦耳动听起来,平时不太常见的拒人于千里之外的这些汉字也不再那么陌生, ...
- java语言仅支持单重继承_java语言程序设计基础篇习题_复习题_第十一章
java语言程序设计基础篇习题_复习题_第十一章 11.1 下面说法是真是假?一个子类是父类的子集. 11.2 使用什么关键字来定义一个子类 11.3 什么是单一继承?什么是多重继承?java支持多重 ...
最新文章
- System Center 2012 R2 CM系列之Configuration Manager介绍
- Eclipse常用设置
- 曾今的代码系列——获取当天最大流水号存储过程
- java实现二进制转十六进制
- COG、XR、X5R、Y5V电容器分类
- php 获取文件给用户下载,php 下载文件/直接下载数据内容
- LeetCode 910. 最小差值 II(贪心)
- k近邻算法(KNN)-分类算法
- 使用电脑adb给Essential Phone刷机 —(官方篇)
- 监听滚动条和浏览器大小变化
- day4-Python学习笔记(七)函数与模块
- [HTTP协议] 基础知识
- 深度学习大厂前端项目开发全流程全流程
- 区块链技术对大数据有哪些影响
- 微星主板黑苹果_组装电脑哪个主板好?如何选择电脑主板?2020年电脑主板推荐及分析。...
- 复制iPhone端百度网盘下载好的视频到电脑(Mac / Windows)- iOS 12.4
- hbase数据库详解
- 为什么是“深度”学习而不是宽度?
- word里双横线怎么打_word怎么加双下划线
- GBT 31000-2015 社会治安综合治理基础数据规范 数据项 编码