目录

  • Floyd(弗洛伊德)算法
  • Dijkstra(迪杰斯特拉)算法
  • 联想:贪心与动态规划——不恰当的贪心导致出错

没有学过算法,请各位大佬们轻拍

本文将简单比较一下图论中最短路的两大最短路算法:Floyd(弗洛伊德)算法与Dijkstra(迪杰斯特拉)算法,并阐述一下两大算法背后的算法原理(动态规划与贪心),并记录一下由于对算法本质理解不透彻,我是怎么把自己坑了。

Floyd(弗洛伊德)算法

Floyd算法本质上是一种动态规划算法,又称“插点法”。可以形象的解释为“如果两点间的路径长度,大于这两点通通过第三点连接的路径长度,那么就修正这两点的最短路径”。

Floyd算法的Java实现如下

public class GraphAlgorithm {public static final int INFINITY = Integer.MAX_VALUE >> 4;public static void floyd(HashMap<Integer, HashMap<Integer, Integer>> graph) {for (Integer k : graph.keySet()) {for (Integer i : graph.keySet()) {if (k.equals(i)) {continue;}int ik = graph.get(i).get(k);if (ik == INFINITY) {continue;}for (Integer j : graph.keySet()) {int ij = graph.get(i).get(j);int kj = graph.get(k).get(j);if (ik + kj < ij) {graph.get(i).put(j, ik + kj);}}}}}
}

非常简明的三重循环,是一个动态规划算法。

就是一个三重循环权值修正,就完成了所有顶点之间的最短路计算,时间复杂度是O(n^3)

其实Floyd算法很好理解和实现,没什么好说的,本质就是动态规划

Dijkstra(迪杰斯特拉)算法

Dijkstra算法本质上是一种贪心算法

迪杰斯特拉算法主要特点是以起始点为中心向外层层扩展,从一个顶点到其余各顶点的最短路径算法,直到扩展到终点为止。

很难受。Dijkstra算法是一种单源最短路算法,在算法的缓存优化中,我忽略了必须是最短路为真的条件必须是“其余n-1个节点均得到最短路径”

下面是错误的堆优化并缓存的dijkstra代码,然后分析原因

public class GraphAlgorithm {public static final int INFINITY = Integer.MAX_VALUE >> 4;// 堆中保存的数据节点public class HeapNode implements Comparable {private int value;private int id;public HeapNode(int id, int value) {this.value = value;this.id = id;}public int getValue() {return value;}public int getId() {return id;}@Overridepublic int compareTo(Object o) {return Integer.compare(value, ((HeapNode) o).getValue());}}// 堆优化的迪杰斯特拉算法public static void dijkstraWithHeap(HashMap<Integer, HashMap<Integer, Integer>> graph,int fromNodeId, int toNodeId) {PriorityQueue<HeapNode> sup = new PriorityQueue<>();HashMap<Integer, Integer> dist = new HashMap<>();Set<Integer> found = new HashSet<>();for (Integer vertex : graph.keySet()) {dist.put(vertex, INFINITY);}dist.put(fromNodeId, 0);sup.add(new HeapNode(fromNodeId, 0));while (!sup.isEmpty()) {HeapNode front = sup.poll();int nowShortest = front.getId();int minWeight = front.getValue();// 此处更新缓存?好像可以?我不知道graph.get(fromNodeId).put(nowShortest, minWeight);graph.get(nowShortest).put(fromNodeId, minWeight);if (nowShortest == toNodeId) { // 致命错误,此处不能结束函数return;}found.add(nowShortest);for (Integer ver : graph.get(nowShortest).keySet()) {int value = graph.get(nowShortest).get(ver);if (!found.contains(ver) && minWeight + value < dist.get(ver)) {dist.put(ver, minWeight + value);sup.add(new HeapNode(ver, minWeight + value));}}}graph.get(fromNodeId).put(toNodeId, INFINITY);graph.get(toNodeId).put(fromNodeId, INFINITY);}
}

Dijkstra是一种贪心算法,所有的最短路都只是基于已知情况做出的判断,所以在堆不为空(朴素Dijkstra是没有遍历完其余n-1个节点)之前不能结束算法,否则得到的答案可能是错误的。

此前没有发现这个问题是因为数据量不够大,只有1000余条指令,所以这样的Dijkstra算法没有出错。

当数据量增大到5000条,其中384条最短路查询指令,有13条出错。仔细排查后才发现是Dijkstra的问题。(然而这时候提交时间已经截至了,C组预定?)

而Dijkstra算法不止最短路矩阵使用了,最少换成、最少票价、最小不满意度矩阵均使用了Dijkstra算法,但这些指令没有出错。我认为原因如下:图的邻接表在数据量大的情况下,是一个稠密图,Dijkstra算法提前结束会导致缓存结果并非实际的最短路。

主要还是没有理解贪心算法的本质,导致了错误的修改。

贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,贪心算法所做出的是在某种意义上的局部最优解。

以后一定好好学习算法。不知道以后算法课会不会很难……

那么正确的缓存方式应该是这样:

public class GraphAlgorithm {public static final int INFINITY = Integer.MAX_VALUE >> 4;// 堆优化的迪杰斯特拉算法public static void dijkstraWithHeap(HashMap<Integer, HashMap<Integer, Integer>> graph,int fromNodeId, int toNodeId) {PriorityQueue<HeapNode> sup = new PriorityQueue<>();HashMap<Integer, Integer> dist = new HashMap<>(graph.size());Set<Integer> found = new HashSet<>();for (Integer vertex : graph.keySet()) {dist.put(vertex, INFINITY);}dist.put(fromNodeId, 0);sup.add(new HeapNode(fromNodeId, 0));while (!sup.isEmpty()) {HeapNode front = sup.poll();int nowShortest = front.getId();int minWeight = front.getValue();if (found.contains(nowShortest)) {continue;}found.add(nowShortest);for (Integer ver : graph.get(nowShortest).keySet()) {int value = graph.get(nowShortest).get(ver);if (!found.contains(ver) && minWeight + value < dist.get(ver)) {dist.put(ver, minWeight + value);sup.add(new HeapNode(ver, minWeight + value));}}}// 最后缓存数据for (Integer ver : dist.keySet()) {int minWeight = dist.get(ver);graph.get(fromNodeId).put(ver, minWeight);graph.get(ver).put(fromNodeId, minWeight);}}
}

本来可以是开心的A组,开心的满分,结果……唉?

联想:贪心与动态规划——不恰当的贪心导致出错

关于贪心和动态规划,让我想起来了一类很经典的题型,最少的钱的张数:

现在有5元、4元、3元以及1元的纸币,问7元最少要多少张纸币?

如果按照简单的贪心策略,就是7 = 5 + 1 + 1,但这显然是错的,显然7 = 4 + 3才是最优解。

如果是动态规划就不存在这个问题。

原题我记不清楚了,只记得大概坑点就是这个。当时看了题解才知道坑点是这个。

(可惜当时太菜了不懂啥事动态规划,现在也菜)

大概就这样。算法真有趣。

请大佬们多多补充,说的不对或者不好的纠正一下。


2019.5.16

我果然强测凉了?果然C组?

转载于:https://www.cnblogs.com/migu3552/p/10870622.html

【面向对象】记一次错误的Dijkstra算法优化—动态规划与贪心相关推荐

  1. 算法学习--动态规划与贪心算法

    动态规划与贪心算法都是一种递推算法,都是用局部最优解来推导全局最优解:是对遍历解空间的一种优化:当问题具有最优子结构时,可以用动态规划来解决,而贪心算法是动态规划的特例 动态规划 1. 动态规划的思想 ...

  2. 记一次错误使用雪花算法引起的数据库主键冲突和解决时钟回拨问题

    在分布式系统中,有一些需要使用全局唯一 ID 的场景,这种时候为了防止 ID 冲突可以使用 36 位的 UUID,但是 UUID 有一些缺点,首先他相对比较长,另外 UUID 一般是无序的 有些时候我 ...

  3. dijkstra算法优化

    如果有向图中边的权重是正整数时,可以优化 #include <iostream> #include <limits> #include <algorithm> #i ...

  4. Dijkstra算法、Floyd算法的区别与联系,并由此谈到greedy和DP

    首先,Dijkstra算法与Floyd算法都是广度优先搜索的算法.都可以用来求单源点到其他所有点的最短路径.那么这两者的原理分别是怎样?彼此又有什么区别呢? 求此有向图中起点1到其他所有点的最短距离 ...

  5. Dijkstra算法的思想和数学归纳法

    ospf协议很多人都知道,很多人也会配置而且很熟练,但是很少有人懂得其背后的思想是什么,Dijkstra算法是求解单源最短路径的绝妙算法之一,我打心眼里头喜欢这个算法,真想把之一去掉.Dijkstra ...

  6. 基于dijsktra算法的最短路径求解_基于dijkstra算法的AGV路径规划(含C++代码)

    文字&代码来源: @Wasabi喵喵喵 基于dijkstra算法的AGV路径规划 dijkstra算法的路径规划 经典Dijkstra算法是一种贪心算法,根据路径长度递增次序找到最短路径,通常 ...

  7. Dijkstra算法与其最小堆优化

    (仿佛回到了当年打比赛的时候呢 POJ 3013(Big Christmas Tree) 传送门:http://poj.org/problem?id=3013 题目大意:由一堆顶点和边构造出一棵圣诞树 ...

  8. dijkstra算法详解—简单易懂

    文章目录 1 简介 2 算法思想与原理 3 具体步骤 4 动态展示 5 代码实现(以邻接矩阵为例) 5.1 基本数据 5.2 初始化 5.3 dijkstra算法核心 5.4 主函数与头文件等 6 拓 ...

  9. 【路径规划】(1) Dijkstra 算法求解最短路,附python完整代码

    好久不见,我又回来了,这段时间把路径规划的一系列算法整理一下,感兴趣的点个关注.今天介绍一下机器人路径规划算法中最基础的 Dijkstra 算法,文末有 python 完整代码,那我们开始吧. 1. ...

最新文章

  1. 为什么三维重建才是计算机视觉的最终归宿?
  2. 7 series FPGA DSP48E介绍
  3. python中怎么安装pip-python中怎么安装pip
  4. 51nod挑的部分5级题
  5. 过去3个多月的1200个小时里,我收获了什么?| 2021年年中总结
  6. 论文浅尝 | GraphSAINT—基于图采样的归纳学习方法
  7. mysql 5.1 db2i_DB2 9.5.0.0升级至9.5.0.9(小版本升级)
  8. 用html设计一个logo页面_如何设计一个Logo?——Bobu Africa旅行品牌Logo设计
  9. WSUS补丁服务器部署详细 利用WSUS部署更新程序
  10. 蓝软服务器文件监控同步系统,蓝软7000ERP通用操作使用教程
  11. repo/git下载android源码断后重新下载
  12. 宾大最新《图神经网络》课程,附视频与课件
  13. linux 启动u盘引导,U盘启动引导安装linux
  14. 【PLSQL】PLSQL安装、破解以及汉化教程
  15. springboot官方文档PDF下载指北
  16. 最新行政区划代码下载
  17. windows10升级助手_微软官网下载与安装windows10系统的操作步骤
  18. [python爬虫]爬取英雄联盟所有英雄数据并下载所有英雄皮肤
  19. Cask ‘libreoffice-still‘ definition is invalid .....unknown or unsupported macOS version: :mavericks
  20. BZOJ 1050 旅行comf

热门文章

  1. 批量导出创建索引的脚本
  2. 如何确定数组中含有某个元素?
  3. <![CDATA[ ]]>的简单使用
  4. dispose用法Java_Java调用Martlab使用dispose()后仍然不能释放内存的问题
  5. 了解PostgreSQL
  6. 计算机专业公共基础课,非计算机专业计算机公共基础课程中计算思维体现的必要性...
  7. 思必驰自研AI芯片不仅方式独特,首代毫瓦级AI语音芯片也仅用1年
  8. 【ajax】ajax详解,ajax是什么?
  9. git commit之后进入vim(vi)界面,如何退出
  10. python技术应用工程师_2020年最受工程师欢迎的技能:Python第一