问题描述

给定一个图,图的节点名称用(000 ~ N−1N - 1N−1)表示。NNN为图的节点个数,MMM为边的个数,SSS为起始点。

输入条件:
第一行输入 NMSN M SNMS。
其后MMM行,每行输入三个数,分别代表源节点目标节点边的距离

输出条件:
请输出SSS到所有点的最短距离,并打印出每一步经过的节点名称(中间以空格隔开)。

测试样例:

输入:
4 5 0
0 1 1
1 3 2
0 3 4
0 2 2
2 3 1输出:
从 0 到 0 的最短距离是:0
所经过的路径是:
0
-----------------------------------
从 0 到 1 的最短距离是:1
所经过的路径是:
0 1
-----------------------------------
从 0 到 2 的最短距离是:2
所经过的路径是:
0 2
-----------------------------------
从 0 到 3 的最短距离是:3
所经过的路径是:
0 1 3
-----------------------------------输入:
5 8 0
0 1 10
0 3 20
0 4 100
1 2 10
2 4 10
3 2 10
3 4 10
1 4 20输出:
从 0 到 0 的最短距离是:0
所经过的路径是:
0
-----------------------------------
从 0 到 1 的最短距离是:10
所经过的路径是:
0 1
-----------------------------------
从 0 到 2 的最短距离是:20
所经过的路径是:
0 1 2
-----------------------------------
从 0 到 3 的最短距离是:20
所经过的路径是:
0 3
-----------------------------------
从 0 到 4 的最短距离是:30
所经过的路径是:
0 1 4
-----------------------------------

算法就不介绍了,慕课浙大数据结构讲的很好。
迪杰斯特拉算法能处理有权单源图的最短路径问题(边权重不能有负值)。

代码思路

  1. 建立邻接数组(邻接链表),并根据已知数据填充数组。
  2. 根据题目需求,建立checked数组、dist数组、path数组、count数组来分别保存节点是否被访问过、最短距离、上一跳、路线个数。并对这些数组做初始化。
  3. 进入大循环,找到一个未处理过,而且具有最小边的节点idist[i]最小)。

    可以通过小顶堆来维护最小的边,也能直接遍历所有节点找出最小边。

  4. 如果找不到,说明图已经处理完了,直接退出。
  5. 如果找到了,将check[i]设为已访问。并访问其相邻节点。
  6. 遍历相邻节点j时,如果从起始点到i,再从ij的距离比直接从起始点到j的距离短的话,更新起始点到j的距离,并将j的上一跳设置为i
  7. 最后得到的dist数组,保存了起始点到所有点的最短距离。path数组保存了从起始点到所有点最短路径的上一跳。根据题目要求输出即可。

代码模板

import java.util.Arrays;
import java.util.Scanner;/*** @Auther: Erekilu* @Date: 2020-06-04*/
public class Dijkstra
{private static final int MAX = 0x3f3f3f3f;public static void main(String[] args){Scanner in = new Scanner(System.in);int count = in.nextInt();int number = in.nextInt();int source = in.nextInt();int[][] line = new int[number][3];for (int i = 0 ; i < number ; i++){line[i][0] = in.nextInt();line[i][1] = in.nextInt();line[i][2] = in.nextInt();}new Dijkstra().road(count, line, source);}/*** 给出单源无向图,计算从起始节到所有节点的最短距离,并打印路径** @param count  节点总数* @param line   边和权重的集合*               [[0, 1, 5], [1, 2, 7], [0, 2, 10]]表示从节点0到节点1的距离是5,节点1到节点2的距离是7,节点0到节点2的距离是10* @param source 起始节点*/public void road(int count, int[][] line, int source){// 邻接矩阵int[][] graph = new int[count][count];// 使用最大值填充邻接矩阵for (int[] slide : graph){Arrays.fill(slide, MAX);}// 初始化邻接矩阵for (int[] L : line){graph[L[0]][L[1]] = L[2];graph[L[1]][L[0]] = L[2];}// 定义距离数组,dist[i]表示从起始点到i的最短距离int[] dist = new int[count];Arrays.fill(dist, MAX);dist[source] = 0;// 定义前驱节点记录,path[i]代表i的前驱节点int[] path = new int[count];path[source] = -1;// checked[i]标识第i个节点是否被处理过int[] checked = new int[count];while (true){// 在所有节点中选择一个距离source最短的节点int tmpMin = MAX;int tmpIndex = -1;for (int i = 0 ; i < count ; i++){// 如果这个节点被处理过,跳过这个节点if (checked[i] == 1)continue;if (dist[i] < tmpMin){tmpMin = dist[i];tmpIndex = i;}}// 如果没找到,退出循环if (tmpIndex == -1)break;// 如果找到了,将checked[i]设为访问过checked[tmpIndex] = 1;// 遍历其所有相邻节点for (int i = 0 ; i < count ; i++){int near = graph[tmpIndex][i];// 第一个是判断这个边是否存在// 第二个是判断对应节点是否处理过// 第三个是判断新的距离是否比旧的距离短if (near != MAX && checked[i] == 0 && dist[tmpIndex] + near < dist[i]){// 更新距离和前驱节点dist[i] = dist[tmpIndex] + near;path[i] = tmpIndex;}}}// 打印最短距离,打印路径for (int i = 0 ; i < count ; i++){System.out.println("从 " + source + " 到 " + i + " 的最短距离是:" + dist[i]);System.out.println("所经过的路径是:");printRoad(path, i);System.out.println("\n-----------------------------------");}}/*** 打印从起始点到目标节点的路径* @param path 前驱数组* @param target 目标节点*/private void printRoad(int [] path, int target){if (path[target] == -1) {System.out.print(target + " ");return;}printRoad(path, path[target]);System.out.print(target + " ");}}

拓展问题:最短路径的条数

如何输出最短路径的个数?
例如从a到e有三种路径可以走,就应该输出3。

不妨分析一下,如果用一个数组count[i]来表示起始点到i的最短路径个数。那么这个count[i]应该如何统计?

  • 当距离要更新时:count[i]=count[pre]count[i] = count[pre]count[i]=count[pre]
  • 当距离相等时:count[i]=count[i]+count[pre]count[i] = count[i] + count[pre]count[i]=count[i]+count[pre]

画个图比较好理解,当起始点到i的距离更新为更小时,最短路径个数要和起始点到先序节点pre的个数一致。当出现了相等的距离时,总数就多了先序节点那么多个(这时不能直接加一,出现一条重复路径后,前面的一堆路径都能通过这个路径走,所以要加上前面一堆路径的个数,也就是count[pre])。

实现过程也比较容易:

  • 新建count数组并初始化。
  • 在遍历某个节点的相邻节点时,不能只在值更小的时候更新count数组,还要在值相等的情况下更新count数组。

替换后的road方法(只有两处有更新,标记在代码中了):

public void road(int count, int[][] line, int source)
{// 邻接矩阵int[][] graph = new int[count][count];// 使用最大值填充邻接矩阵for (int[] slide : graph){Arrays.fill(slide, MAX);}// 初始化邻接矩阵for (int[] L : line){graph[L[0]][L[1]] = L[2];graph[L[1]][L[0]] = L[2];}// 定义距离数组,dist[i]表示从起始点到i的最短距离int[] dist = new int[count];Arrays.fill(dist, MAX);dist[source] = 0;// 定义前驱节点记录,path[i]代表i的前驱节点int[] path = new int[count];path[source] = -1;// pathCount[i]统计从起始点到i有多少条最短路径int[] pathCount = new int[count]; <================保存距离数组pathCount[source] = 1;// checked[i]标识第i个节点是否被处理过int[] checked = new int[count];while (true){// 在所有节点中选择一个距离source最短的节点int tmpMin = MAX;int tmpIndex = -1;for (int i = 0 ; i < count ; i++){// 如果这个节点被处理过,跳过这个节点if (checked[i] == 1)continue;if (dist[i] < tmpMin){tmpMin = dist[i];tmpIndex = i;}}// 如果没找到,退出循环if (tmpIndex == -1)break;// 如果找到了,将checked[i]设为访问过checked[tmpIndex] = 1;// 遍历其所有相邻节点for (int i = 0 ; i < count ; i++){int near = graph[tmpIndex][i];// 第一个是判断这个边是否存在// 第二个是判断对应节点是否处理过// 第三个是判断新的距离是否比旧的距离短 ↓↓↓↓↓↓↓↓↓这段内容有变化↓↓↓↓↓↓↓↓↓if (near != MAX && checked[i] == 0 && dist[tmpIndex] + near <= dist[i]){                               // ↑↑↑↑↑↑↑↑小于号变为小于等于↑↑↑↑↑↑↑↑if (dist[tmpIndex] + near == dist[i]) {pathCount[i] += pathCount[tmpIndex];} else {pathCount[i] = pathCount[tmpIndex];}// ↑↑↑↑↑↑↑↑pathCount的更新↑↑↑↑↑↑↑↑// 更新距离和前驱节点dist[i] = dist[tmpIndex] + near;path[i] = tmpIndex;}}}for (int i = 0 ; i < count ; i++){System.out.println("最短路径个数为:" + pathCount[i]);System.out.println("从 " + source + " 到 " + i + " 的最短距离是:" + dist[i]);System.out.println("所经过的路径是:");printRoad(path, i);System.out.println("\n-----------------------------------");}
}

如果要打印所有的最短路径,只需将path数组从int []变为int [][],遇到相同距离就添加进去。打印的话打印所有前驱节点,然后这些前驱节点继续递归打印所有前驱节点即可。

拓展问题:打印经过节点数最少的最短路径

在有多条最短路径的情况下,只选择经过节点数最少的最短路径

这个问题可以转化为双重条件,主条件是距离,副条件是节点数。

优先判断距离。距离相等的情况下,再判断节点数大小。

典型迪杰斯特拉变式:PTA 旅游规划(有权单源最短路径)

迪杰斯特拉算法及变式(最短距离,打印路径,最短经过节点数)相关推荐

  1. 用迪杰斯特拉算法实现地铁的站点搜索

    上一篇文章,利用迪杰斯特拉(dijkstra)算法,实现了无向图的最短路径搜索功能.本篇将以南京地铁为例,用迪杰斯特拉算法实现两个站点之间的最短路径搜索. 借用百度百科,南京2015年4月份的地铁运行 ...

  2. 求有向图中两点最短距离java_Java 迪杰斯特拉算法实现查找最短距离

    迪杰斯特拉算法 迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法.是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题.迪杰斯特拉算法主要特点是 ...

  3. 图 相关算法~从头学算法【广搜、 深搜、 拓扑排序、 并查集、 弗洛伊德算法、迪杰斯特拉算法】

    图的相关主流算法主要有: 广度优先搜索 深度优先搜索 拓扑排序 并查集 多源最短路径(弗洛伊德算法) 单源最短路径(迪杰斯特拉算法) 其中呢,最基本的是前两种,也就是平时常用的广搜和深搜,本文中将概要 ...

  4. 图解迪杰斯特拉算法(最短路径问题)

    文章目录 一.单源最短路径问题 二.迪杰斯特拉算法 2.1 什么是迪杰斯特拉算法 2.2 迪杰斯特拉算法的步骤 2.2.1 基本步骤 2.2.2 图解演示 2.3 迪杰斯特拉算法的代码实现 一.单源最 ...

  5. 迪杰斯特拉算法——PAT 1003

    本文主要是将我对于我对于迪杰斯特拉算法的理解写出来,同时通过例题来希望能够加深对于算法的理解,其中有错误的地方希望大家指正. 迪杰斯特拉算法 我将这个算法理解成一个局部到整体的算法,这个方法确实越研究 ...

  6. 狄斯奎诺算法 c语言,图的邻接表实现迪杰斯特拉算法(C语言).doc

    图的邻接表实现迪杰斯特拉算法(C语言) /*迪杰斯特拉算法(狄斯奎诺算法)解决的是从源点到其它所有顶点的最短路径问题*/ //算法实现: #include #include #define MAX 2 ...

  7. 【数据结构】图的应用(普利姆算法、克鲁斯卡尔算法、迪杰斯特拉算法、弗洛伊德算法、拓扑排序)

    最小生成树 什么是最小生成树 是一棵树 - 无回路 - |V|个顶点一定有|V|-1条边 是生成树 - 包含全部顶点 - |V|-1条边全在图里 贪心算法 什么是"贪":每一步都要 ...

  8. 数据结构——图-迪杰斯特拉算法

    问题描述 将图以邻接矩阵或邻接表存储,实现Dijkstra算法. 算法设计 迪杰斯特拉算法: 1.假设用带权的邻接矩阵arc,来表示带权有向图,arc[i][j],表示弧<vi,vj>上的 ...

  9. 迪杰斯特拉算法(最短路径)

    描述 算法过程 代码实现 package com.atguigu.dijkstra;import com.sun.xml.internal.fastinfoset.algorithm.BooleanE ...

最新文章

  1. boot.ini文件解密
  2. python源码编译 带tkinter_python通过Tkinter库实现的一个简单的文本编辑器源码
  3. 生产者-消费者模式的实现
  4. 《码出高效 Java开发手册》第八章 单元测试 (未整理)
  5. 戴尔科技集团公布 2019 财年第四季度及全年财报,巨大进步和强劲发展的一年...
  6. JS数组的相关操作(循环、查找、过滤、排序等)
  7. PHP Notice: undefined index xxx
  8. 论文赏析[EMNLP18]针对自顶向下和中序移进归约成分句法分析的Dynamic Oracles
  9. CvArr、Mat、CvMat、IplImage、BYTE转换
  10. JDBC连接效率问题
  11. docker删除es数据_docker使用系列之-(6).docker常用命令
  12. linux常用的搜索命令
  13. python制作奖状,从excel表格中导出数据,取前20名,做成png奖状,再放入ppt中
  14. httpf发送 json_https和http的post发送总结
  15. cipher 加密解密
  16. 高德地图定位 地图比例缩放
  17. Dell笔记本 BIOS改硬盘模式Raid改为ahci,开机蓝屏0xc0000001
  18. MAX708SCUA
  19. 如何用tensorflow使用自定义数据来训练,做物体检测
  20. 登录页面渗透测试思路与总结

热门文章

  1. 大二的第一次社会毒打
  2. Windows版本,OS内核版本,Windows SDK之间的关系(附 :Windows纯净系统下载以及更新)
  3. rabbitmq入门(四)Topics主题模式
  4. 软件的版权和专利辨析
  5. 安徽省美术作品版权登记技巧,申请了商标还要申请美术作品版权吗?
  6. AE教程丨1分钟学会制作信号故障风特效
  7. python闲鱼二手爬虫_Python 爬虫咸鱼版
  8. Android实现动态贴纸,Android开发之仿微博贴纸效果实现——进阶篇
  9. 小程序实现地图导航功能
  10. STP生成树协议切割网络环路