最短路径:迪杰斯特拉算法

简介

        英文名Dijkstra

        作用:找到路中指定起点到指定终点的带权最短路径

核心步骤

        1)确定起点,终点

        2)从未走过的点中选取从起点到权值最小点作为中心点

        3)如果满足 起点到中心点权值 + 中心点到指定其他点的权值 < 起点到其他点的权值,

        即Weight[start] [center] +Weight [center] [other] < Weight [start] [center] ,

        简言之,有更短的路径就取更短的路

理论模拟

        以A为起点,D为终点,如图所示 径, 更新记录更短权值路径

 从未走过的点中选取权值最小点,即A作为中心点,标记A走过,更新起点到B、F、G的路径

 

从未走过的点中选取权值最小点,即B, 并且W:B->C + W:A->C = 12 + 10 < +oo ,更新起点A到C的路径和,

即W: A-> C =W: A-> B -> C =12+10 =22

 

 继续从未走过的点中选取权值最小点G, W: A -> E =+oo > W: A->G ->E =14+8 =22 ,

 更新W: A->E 为22

选取F, 由于W:A->F->E=16+2 =18 <22 更新 W: A-> E =18 ,

 选取E,由于W:A->E->D=18+4=22<+oo,则更新W: A->D =22

 选取C,无可更新点

 到达终点D! 最短路径为A->F->E->D ,最短路径和为22

 

Java代码实现
 顶点
//顶点类
public class Vertex {public String Number;  //顶点编号public List<Vertex>neighborVertexs;    //邻居顶点public Map<Vertex,Integer>weights;     //与邻居节点之间的权值public Vertex(String number) {this.Number = number;this.neighborVertexs=new LinkedList<>();this.weights=new HashMap<>();}
}
public class Edge {public Vertex start;public Vertex end;public Integer weight;public Edge(Vertex start, Vertex end, Integer weight) {this.start = start;this.end = end;this.weight = weight;}
}
最短路径返回结果
public class MinPathResult {public String minPathString;    //将最短路径拼接成字符串形式,如 A->B->Cpublic List<Vertex>minPathList; //将起点到终点的路径储存在List集合中public Integer minPathSum;  //记录起点到终点的最短路径和public MinPathResult(List<Vertex> minPathList, String minPathString,Integer minPathSum) {this.minPathString = minPathString;this.minPathList = minPathList;this.minPathSum=minPathSum;}@Overridepublic String toString() {return "Result{" +"minPathString:'" + minPathString +"  minPathSum:"+minPathSum+'}';}
}
Dijkstra算法的实现,适用于无向图
import java.util.*;
//适用于无向图
public class DijkstraOperator {private List<Vertex>vertexs;    //全部顶点private List<Edge>edges;        //所有边private Map<String,Vertex>vertexs_map;  //通过顶点编号找到顶点private final static Integer INF=Integer.MAX_VALUE;     //代表无穷大public DijkstraOperator(List<Vertex> vertexs, List<Edge> edges) {this.vertexs = vertexs;this.edges = edges;this.vertexs_map=new HashMap<>();//构建编号映射顶点for(Vertex v:vertexs){vertexs_map.put(v.Number,v);}//填充所有顶点的邻居以及权值for(int i=0;i<edges.size();i++){//填充起点的邻居,以及起点到终点的权值edges.get(i).start.neighborVertexs.add(edges.get(i).end);edges.get(i).start.weights.put(edges.get(i).end,edges.get(i).weight);//填充终点的邻居,以及终点到起点的权值edges.get(i).end.neighborVertexs.add(edges.get(i).start);edges.get(i).end.weights.put(edges.get(i).start,edges.get(i).weight);}}//获得从起点到终点之间的路径public MinPathResult getMinPath(String start, String end){//用哈希表标记某个顶点是否走过Map<Vertex,Boolean>visited=new HashMap<>();//用哈希表记录顶点的前驱Map<Vertex,Vertex>preVertex=new HashMap<>();//利用哈希表记录起点到任意一点的最短路径Map<Vertex,Integer>minPath=new HashMap<>();//初始化三个表for(int i=0;i<vertexs.size();i++){//初始化每一个点都未走过visited.put(vertexs.get(i),false);//初始化每个点的前驱都是自己preVertex.put(vertexs.get(i),vertexs.get(i));//初始化起点到任意两个点之间的最短路径都是无穷大minPath.put(vertexs.get(i),INF);}Vertex startVertex=vertexs_map.get(start);Vertex endVertex=vertexs_map.get(end);//填充存在的路径for(int i=0;i<startVertex.neighborVertexs.size();i++){//设置起点与邻居节点之间的权值minPath.put(startVertex.neighborVertexs.get(i),startVertex.weights.get(startVertex.neighborVertexs.get(i)));//设置点前驱preVertex.put(startVertex.neighborVertexs.get(i),startVertex);}//自己到自己的距离为0minPath.put(startVertex,0);Vertex curVertex=null;//一直寻路,直到找到终点while(curVertex!=endVertex){Integer minWeight=Integer.MAX_VALUE;curVertex=null;//能看到的点之间选取距离最小的那个,且这个点并没有走过for(Vertex v:minPath.keySet()){if(!visited.get(v)&&minPath.get(v)<minWeight){//切换中心点curVertex=v;//更新最小权值minWeight=minPath.get(v);}}//如果找不到下一个中心点,说明从起点根本到达不来终点if(curVertex==null)return null;//标记选取点visited.put(curVertex,true);//更新权值for(int i=0;i<curVertex.neighborVertexs.size();i++){//邻居节点Vertex neighborVertex=curVertex.neighborVertexs.get(i);//计算起点到邻居节点之间新的权值int newWeight=minPath.get(curVertex)+curVertex.weights.get(neighborVertex);//找到能移动的点,如果转折之后距离更短,则记录更短的距离if(visited.get(neighborVertex)==false&&newWeight<minPath.get(neighborVertex)){//记录更短距离minPath.put(neighborVertex,newWeight);//记录邻居节点的前驱preVertex.put(neighborVertex,curVertex);}}}//起点到终点之间的最短路径LinkedList<Vertex>targetPath=new LinkedList<>();for(Vertex curVer=endVertex;curVer!=startVertex;curVer=preVertex.get(curVer)){targetPath.addFirst(curVer);}targetPath.addFirst(startVertex);//拼接最短路径StringBuffer minPathStringBuffer=new StringBuffer();Integer pathSum=0;for(int i=0;i< targetPath.size();i++){minPathStringBuffer.append(targetPath.get(i).Number);if(i!= targetPath.size()-1){pathSum=pathSum+targetPath.get(i).weights.get(targetPath.get(i+1));minPathStringBuffer.append("->");}}return new MinPathResult(targetPath, minPathStringBuffer.toString(),pathSum);}
}
测试函数
import java.util.*;public class Main {public static void main(String[] args) {Scanner scanner=new Scanner(System.in);List<Vertex>vertexs=new LinkedList<>();List<Edge>edges=new LinkedList<>();System.out.println("请输入顶点的数量:");Integer vexcnt= scanner.nextInt();System.out.println("请输入这些顶点编号:");for(int i=0;i<vexcnt;i++){vertexs.add(new Vertex(scanner.next()));}System.out.println("请输入边的数量:");Integer edgecnt= scanner.nextInt();System.out.println("请输入这些边的端点编号和权值:");for(int i=0;i<edgecnt;i++){String number1= scanner.next();String number2= scanner.next();Integer weight= scanner.nextInt();Vertex v1=null;Vertex v2=null;for(int j=0;j<vertexs.size();j++){if(vertexs.get(j).Number.equals(number1))v1=vertexs.get(j);if(vertexs.get(j).Number.equals(number2))v2=vertexs.get(j);}edges.add(new Edge(v1,v2,weight));}//定义迪杰斯特拉操作类DijkstraOperator dijkstra=new DijkstraOperator(vertexs,edges);//获取任意两点之间的最短路径结果集List<MinPathResult>minPathResults=new ArrayList<>();for(int i=0;i< vertexs.size();i++){for(int j=i+1;j< vertexs.size();j++){minPathResults.add(dijkstra.getMinPath(vertexs.get(i).Number,vertexs.get(j).Number));System.out.println(minPathResults.get(minPathResults.size()-1));}}}
}
测试输入与输出结果
//输入部分
请输入顶点的数量:
7
请输入这些顶点编号:
A B C D E F G
请输入边的数量:
12
请输入这些边的端点编号和权值:
A B 12
A F 16
A G 14
B C 10
B F 7
G F 9
G E 8
F C 6
F E 2
C D 3
C E 5
E D 4//输出部分
Result{minPathString:'A->B  minPathSum:12}
Result{minPathString:'A->B->C  minPathSum:22}
Result{minPathString:'A->F->E->D  minPathSum:22}
Result{minPathString:'A->F->E  minPathSum:18}
Result{minPathString:'A->F  minPathSum:16}
Result{minPathString:'A->G  minPathSum:14}
Result{minPathString:'B->C  minPathSum:10}
Result{minPathString:'B->F->E->D  minPathSum:13}
Result{minPathString:'B->F->E  minPathSum:9}
Result{minPathString:'B->F  minPathSum:7}
Result{minPathString:'B->F->G  minPathSum:16}
Result{minPathString:'C->D  minPathSum:3}
Result{minPathString:'C->E  minPathSum:5}
Result{minPathString:'C->F  minPathSum:6}
Result{minPathString:'C->E->G  minPathSum:13}
Result{minPathString:'D->E  minPathSum:4}
Result{minPathString:'D->E->F  minPathSum:6}
Result{minPathString:'D->E->G  minPathSum:12}
Result{minPathString:'E->F  minPathSum:2}
Result{minPathString:'E->G  minPathSum:8}
Result{minPathString:'F->G  minPathSum:9}进程已结束,退出代码为 0

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/123878.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[论文阅读]Ghost-free High Dynamic Range Imaging with Context-aware Transformer

多帧高动态范围成像&#xff08;High Dynamic Range Imaging, HDRI/HDR&#xff09;旨在通过合并多幅不同曝光程度下的低动态范围图像&#xff0c;生成具有更宽动态范围和更逼真细节的图像。如果这些低动态范围图像完全对齐&#xff0c;则可以很好地融合为HDR图像&#xff0c;但…

RTMP直播在虚拟数字人场景使用

虚拟数字人&#xff08;Virtual Digital Human&#xff09;&#xff0c;指的是一种基于数字技术创建的虚拟人物&#xff0c;他们有自己的外貌、声音&#xff0c;甚至是性格。虚拟数字人通常是通过计算机图形学、人工智能和其他先进技术来实现的。人们可以与这些虚拟数字人进行交…

Xamarin.Forms更改AndroidManifest.xml导致错误:没有兼容的代码在线程上运行

想在APP中加一个打开摄像头的功能&#xff0c;按照该博主的方法&#xff1a;https://blog.csdn.net/zhenweied09/article/details/82287761 设置好后&#xff0c;再运行就出现上图的错误&#xff0c;于是查找原因&#xff0c;定位到是更改AndroidManifest.xml文件导致的&#…

QMI8658A_QMC5883L(9轴)-EVB 评估板

1. 描述 QMI8658A_QMC5883L(9轴)-EVB 评估板是一款功能强大的9轴IMU传感器&#xff0c;它利用了QMA8658A 内置的3轴加速度计和3轴陀螺仪&#xff0c;同时结合QMC5883L的3轴地磁数据&#xff0c;来测量物体在三维空间中的角速度和加速度&#xff08;严格意义上的IMU只为用户提供…

Flash模拟EEPROM原理浅析

根据ST的手册&#xff0c;我们可以看到&#xff0c;外挂EEPROM和Dflash模拟EEPROM&#xff0c;区别如下&#xff1a; 很明显&#xff0c;模拟EEprom的写入速度要远远快于外挂eeprom(有数据传输机制)&#xff1b; 其次&#xff0c;外挂EEPROM不需要擦除即可实现写入数据&#xf…

Wpf 使用 Prism 实战开发Day03

一.实现左侧菜单绑定 效果图: 1.首先需要在项目中创建 mvvm 的架构模式 创建 Models &#xff0c;放置实体类。 实体类需要继承自Prism 框架的 BindableBase&#xff0c;目的是让实体类支持数据的动态变更! 例如: 系统导航菜单实体类 / <summary>/// 系统导航菜单实体类…

【Python学习】—面向对象(九)

【Python学习】—面向对象&#xff08;九&#xff09; 一、初识对象 类中不仅可以定义属性来记录数据&#xff0c;也可以定义函数&#xff0c;用来记录行为&#xff0c;类中定义的属性&#xff08;变量&#xff09;我们称之成员变量&#xff0c;类中定义的行为&#xff08;函数…

【多态-动态绑定-向上转型-抽象类】

文章目录 静态绑定动态绑定多态的具体实现向上转型多态的优缺点抽象类抽象类的作用 总结 静态绑定 重载就是典型例子 动态绑定 多态的具体实现 //多态 class Animal{public String name;public int age;//无参构造方法public Animal() {}//有参构造方法public Animal(Strin…

MySQL Server 5.5 软件和安装配置教程

MySQL 5.5.58&#xff08;32/64位&#xff09;下载链接&#xff1a; 百度网盘&#xff1a;百度网盘 请输入提取码 提取密码&#xff1a;7act 软件简介&#xff1a; MySQL 是由瑞典MySQL AB 公司开发一个关系型数据库管理系统&#xff0c;目前属于 Oracle 旗下产品。MySQL 是最…

代码没注释?一个方法几百行?

干程序员的都有接收别人的代码的经历&#xff0c;大部分时候&#xff0c;我们都会偷偷骂一句“这人是傻逼吧&#xff0c;这代码写的这么烂&#xff01;” “一个方法写几百行&#xff0c;还没有注释&#xff0c;鬼知道写的什么东西&#xff01;” 现在&#xff0c;你不需要为…

__707设计链表

单向链表设计 package 日常Java程序测试.代码随想录.链表;public class __707设计链表__单向链表设计 {class MyLinkedList {//我们首先需要自己定义属性出来int val;MyLinkedList next;int size; //记录链表大小//MyLinkedList() 初始化 MyLinkedList 对象。public MyLinke…

2.flink编码第一步(maven工程创建)

概述 万里第一步&#xff0c;要进行flink代码开发&#xff0c;第一步先整个 flink 代码工程 flink相关文章链接 flink官方文档 两种方式 一种命令行 mvn 创建&#xff0c;另一种直接在 idea 中创建一个工程&#xff0c;使用 mvn 的一些配置 mvn命令行创建 mvn 创建flink工程&…

吴恩达《机器学习》1-4:无监督学习

一、无监督学习 无监督学习就像你拿到一堆未分类的东西&#xff0c;没有标签告诉你它们是什么&#xff0c;然后你的任务是自己找出它们之间的关系或者分成不同的组&#xff0c;而不依赖于任何人给你关于这些东西的指导。 以聚类为例&#xff0c;无监督学习算法可以将数据点分成…

《微习惯》-微习惯策略的八大规则

绝不要自欺欺人满意每一个进步经常回报自己&#xff0c;尤其在完成微习惯之后保持头脑清醒感到强烈抵触时&#xff0c;后退并缩小目标提醒自己这件事很轻松绝不要小看微步骤用多余精力超额完成任务&#xff0c;而不是制定更大目标

LeetCode383. Ransom Note

文章目录 一、题目二、题解 一、题目 Given two strings ransomNote and magazine, return true if ransomNote can be constructed by using the letters from magazine and false otherwise. Each letter in magazine can only be used once in ransomNote. Example 1: I…

接口测试,一篇搞定

大多数人对于接口测试都觉得是一种高大上的测试&#xff0c;觉得学会接口测试就可以从小白测试员&#xff0c;变成了高级测试员&#xff0c;但其实接口测试只是测试的基础内容 什么是接口 接口泛指实体把自己提供给外界的一种抽象化物&#xff08;可以为另一实体&#xff09;&…

9、电路综合-基于简化实频的任意幅频响应的微带电路设计

9、电路综合-基于简化实频的任意幅频响应的微带电路设计 网络综合和简化实频理论学习概述中的1-8介绍了SRFT的一些基本概念和实验方法&#xff0c;终于走到了SRFT的究极用途&#xff0c;给定任意响应直接综合出微带电路。 1、任意幅频响应的微带电路设计用途 我们演示了采用…

Django的静态文件目录(路径)如何配置?

通常用下面的三条语句配置Django的静态文件目录 STATICFILES_DIRS [os.path.join(BASE_DIR, static)] STATIC_URL /static/ STATIC_ROOT os.path.join(BASE_DIR, /static)那么这三条语句分别的作用是什么呢&#xff1f; 请参考博文 https://blog.csdn.net/wenhao_ir/articl…

STM32单片机智能小车一PWM方式实现小车调速和转向

目录 1. 电机模块开发 2. 让小车动起来 3. 串口控制小车方向 4. 如何进行小车PWM调速 5. PWM方式实现小车转向 1. 电机模块开发 L9110s概述 接通VCC&#xff0c;GND 模块电源指示灯亮&#xff0c; 以下资料来源官方&#xff0c;具体根据实际调试 IA1输入高电平&#xff…

添加主仓库后报错error: remote upstream already exists.

可能的原因 远程名 upstream 已经被使用&#xff1a; 这通常意味着你在之前已经添加了一个名为 upstream 的远程仓库。 解决方案 检查现有的远程仓库&#xff1a; 运行 git remote -v 来查看所有配置的远程仓库。这个命令会列出所有远程仓库的URL&#xff0c;你可以检查是否已…