使用基于邻接表的Dijkstra算法求解Project Euler问题

[color=black][b][size=medium]Project Euler中的几个问题[/size][/b][/color]

  首先,来看一看[url=http://projecteuler.net]Project Euler[/url]上的第81到83题。这几个题目的前提条件是一样的,已知一个[url=http://projecteuler.net/project/matrix.txt]80×80的矩阵[/url](由正整数组成)
  [url=http://projecteuler.net/index.php?section=problems&id=81]81题[/url]:[color=green]Find the minimal path sum, in the 80 by 80 matrix, from the top left to the bottom right by only moving right and down.[/color]
  其意思是:[color=orange]只允许从上往下或从左到右,找一条从这个矩阵左上角到右下角的路径,使得路径上的数字之和最小。[/color]

  [url=http://projecteuler.net/index.php?section=problems&id=82]82题[/url]:[color=green]Find the minimal path sum, in the 80 by 80 matrix, from the left column to the right column,by only moving up, down, and right.[/color]
  该题的意思是:[color=orange]允许从上到下或从下到上或从左到右移动,找一条从该矩阵最左列到最右列的路径,使得路径上的数字之和最小。[/color]

  [url=http://projecteuler.net/index.php?section=problems&id=83]83题[/url]:[color=green]Find the minimal path sum, in the 80 by 80 matrix, from the top left to the bottom right by moving left, right, up, and down.[/color]
  翻译过来就是:[color=orange]可以上下左右移动,找一条从该矩阵左上角到右下角的路径,使得路径上数字之和最小。[/color]

  这几个题非常类似,都是从一个给定矩阵找一条路径使得上面数字之和最小。只不过移动的方式越来越多,因此可以想象这几个题目的难度也是越来越大。如果对动态规划比较熟悉的话,很容易可以看出81与82题是可以使用动态规划来解决的。只不过81题属于典型的动态规划题,很容易写出代码,而82题稍稍麻烦了一点。
  不过这里我不谈怎么使用动态规划来解决这些问题,而是转换一下考察问题的角度,将这几个问题转换成图论中经典的“最短路”问题,然后可以使用同样的方法完美解决之。
  首先,[color=blue]将80×80的矩阵看成一个80×80个顶点的图,如果能够从矩阵(i,j)移动到(u,v),则用一条(i,j)到(u,v)的边将这两个顶点连接起来,并且该边的权即为矩阵在(u,v)处的取值。这样,就将一个矩阵转换为一个带权的有向图。[/color]并且容易看出,题目中要求的“数字之和最小的路径”对应该有向图的一个“最短路”。这三个题的区别只在于顶点与顶点之间连接的边不一样。


[color=black][b][size=medium]Dijkstra算法与实现[/size][/b][/color]

  图论中关于求“最短路”问题的算法有很多,著名的有Floyd-Warshall算法,Bellman-Ford 算法etc。不过,Floyd-Warshall算法虽然实现简单,但时间复杂度是O(n^3),而这里n = 80*80 = 6400,使用Floyd-Warshall算法时间上无法接受。另外,这三个题中涉及到的有向图都属于[color=orange]稀疏图[/color],所以我采用了基于图的邻接表结构的Dijkstra算法,这个实现的时间复杂度是O(e×log e),其中e表示边的条数。由于这三个题中e = O(v)(v指图的顶点个数),因此最后我们得到了时间复杂度为O(v log v)的解法(这些题中,v = 80*80)。下面是使用Scala实现的Dijkstra算法:
/**
&#Graph.scala
utils for graph algorithm
@author Eastsun
*/
package eastsun.math

object Graph {
/**
This is an implementation of Dijkstra's algorithm to find the shortest path for a directed
graph with non-negative edge weights.
*/
def dijkstra(size :Int,start :Int,lst :Int=> Iterable[(Int,Int)]):Array[Int] = {
import java.lang.Integer.{ MAX_VALUE => INF }
implicit def t2o(t :(Int,Int)) = new Ordered[(Int,Int)]{
def compare(that :(Int,Int)) = that._2 - t._2
}
val pq = new scala.collection.mutable.PriorityQueue[(Int,Int)]
val dist = Array.make(size,INF)
val mark = Array.make(size,false)
pq += start->0
while(!pq.isEmpty){
val (idx,dst) = pq.dequeue
if(!mark(idx)){
mark(idx) = true
dist(idx) = dst
for((i,d) <- lst(idx);if dist(i)>dst+d){
dist(i) = dst+d
pq += i->dist(i)
}
}
}
dist
}
}

  考虑到对Scala熟悉的不多,我简单解释一下上面这段代码。首先,函数
    def dijkstra(size :Int,start :Int,lst :Int=> Iterable[(Int,Int)]):Array[Int] 

有三个参数,其中:
    size    [color=orange]表示要考虑的有向图的阶[/color](也就是顶点个数)
    start    [color=orange]要求的最短路的起始点[/color]
    lst     [color=orange]一个参数为Int返回值为Iterable[(Int,Int)]的函数。lst(k)将返回图的第k个顶点对应的邻接表,邻接表的每个节点保存两个值(idx,dst)。其中idx表示顶点k到顶点idx有一条边,dst表示这条边的权值。[/color]
返回值为一个整型数组Array[Int],该数组保存了最终结果,其长度为size,第k个元素的值表示从顶点start到顶点k的最短距离,如果不能到达,则为Integer.MAX_VALUE。

  其次,看一下这段代码:
        implicit def t2o(t :(Int,Int)) = new Ordered[(Int,Int)]{
def compare(that :(Int,Int)) = that._2 - t._2
}
val pq = new scala.collection.mutable.PriorityQueue[(Int,Int)]

这段代码的功能是new了一个优先队列pq,该优先队列里面保存的数据类型为(idx,dst)。其中idx为顶点的序号,而dst为距离。并且规定了一个顺序Ordered[(Int,Int)],使得优先队列保持dst最小的在最上面。
  可以计算,上面的Dijkstra实现的时间复杂度为O(e log e)。


[color=black][b][size=medium]解题代码[/size][/b][/color]
  有了上面的介绍,下面直接给出Project Euler这几个问题的代码,可以看到,这几个问题的解题代码非常一致(82题略有不同)
81题的解题代码:
import eastsun.math.Graph._
import scala.io.Source._

object Euler081 extends Application {
val mtx = fromFile("matrix.txt").getLines.map{ line =>
line.split(",").map(_.trim.toInt)
}.toList.toArray

val LEN = mtx.size
val SIZE = LEN*LEN
def lst(n :Int):List[(Int,Int)] = {
val (x,y) = (n/LEN,n%LEN)
var ls = Nil:List[(Int,Int)]
if(x < LEN-1) ls = (n+LEN,mtx(y)(x+1))::ls
if(y < LEN-1) ls = (n+1,mtx(y+1)(x))::ls
ls
}
println(dijkstra(SIZE,0,lst)(SIZE-1)+mtx(0)(0))
}


82题的解题代码:
import scala.io.Source._
import eastsun.math.Graph._

object Euler082 extends Application {
val mtx = fromFile("matrix.txt").getLines.map{ line =>
line.split(",").map(_.trim.toInt)
}.toList.toArray
val LEN = mtx.size
val SIZE = LEN*LEN
def lst(n :Int):List[(Int,Int)] = {
val (x,y) = (n/LEN,n%LEN)
var ls = Nil:List[(Int,Int)]
if(y > 0) ls = (n-1,mtx(y-1)(x))::ls
if(y < LEN-1) ls = (n+1,mtx(y+1)(x))::ls
if(x < LEN-1) ls = (n+LEN,mtx(y)(x+1))::ls
ls
}
val res = 0.until(LEN).map{ n =>
dijkstra(SIZE,n,lst).slice(SIZE-LEN,SIZE).reduceLeft(_ min _)+mtx(n)(0)
}.reduceLeft(_ min _)
println(res)
}


83题的解题代码:
import scala.io.Source._
import eastsun.math.Graph._

object Euler083 extends Application {
val mtx = fromFile("matrix.txt").getLines.map{ line =>
line.split(",").map(_.trim.toInt)
}.toList.toArray
val LEN = mtx.size
val SIZE = LEN*LEN
def lst(n :Int):List[(Int,Int)] = {
val (x,y) = (n/LEN,n%LEN)
var ls = Nil:List[(Int,Int)]
if(y > 0) ls = (n-1,mtx(y-1)(x))::ls
if(y < LEN-1) ls = (n+1,mtx(y+1)(x))::ls
if(x > 0) ls = (n-LEN,mtx(y)(x-1))::ls
if(x < LEN-1) ls = (n+LEN,mtx(y)(x+1))::ls
ls
}

println(dijkstra(SIZE,0,lst)(SIZE-1)+mtx(0)(0))
}
Dijkstra算法邻接表实现 Dijkstra算法C++邻接表实现,用邻接表存图,还有记录路径。 立即下载

相关推荐

Dijkstra-邻接表.cpp

abcde

基于邻接表的Dijkstra算法

根据输入构建邻接表,基于邻接表编写Dijkstra算法求解单源最短路径。优点:避免稀疏矩阵求解单源最短路径时内存空间的浪费。

qq_45528306的博客 481

SAP 屏幕增强:客户商主数据屏幕增强(KNA1、KNB1、KNVV)

本文介绍了SAP系统中针对客户主数据(KNA1、KNB1、KNVV)进行屏幕增强的具体实现方法。主要内容包括:1)在SPRO配置中创建新条目;2)通过SE80创建函数组和程序(LZKNA1TOP等);3)设置子屏幕9001并添加自定义结构字段;4)利用BADI(CUSTOMER_ADD_DATA等)实现数据交互逻辑。文章分别详细说明了针对客户主数据的一般数据(KNA1)、公司代码数据(KNB1)和销售数据(KNVV)三类不同数据的增强配置步骤,包括函数模块创建、屏幕设置和BADI方法调用等关键技术点。

SAP ABAP开发技能记录分享 1620

邻接表实现的Dijkstra算法

一、算法目的 使用邻接表实现Dijkstra算法 使用priority_queue(堆)优化取最小权值边的时间复杂度 从文件中读取的数据格式如下: 二、算法代码 #include <iostream> #include <algorithm> #include <cstring> #include <queue> #include <stdio.h> #include <fstream> #include <sstream&

weixin_44858076的博客 3368

Linux V4L2驱动开发实战:手把手教你用I2C摄像头Sensor注册一个v4l2_subdev

本文详细解析了Linux V4L2驱动开发中I2C摄像头Sensor注册v4l2_subdev的全流程,包括初始化、操作集填充、异步匹配等关键环节。通过实战案例和代码示例,帮助开发者掌握V4L2子系统下的摄像头驱动开发技巧,提升嵌入式Linux系统开发能力。

weixin_30328063的博客 420

Arduino智能小灯DIY:人体感应+光线感应+蓝牙控制全攻略(附完整代码)

本文提供了一份完整的Arduino智能小灯DIY制作指南。项目融合了人体感应、光线感应与蓝牙控制三大功能,通过详细的硬件清单、电路连接图、核心逻辑讲解及附带的完整代码,手把手教你打造一个能自动感知环境与人、并支持手机远程控制的智能照明装置,是入门智能家居和物联网开发的绝佳实践。

java5的博客 1094

dijkstra迪杰斯特拉算法(邻接表法)

使用邻接表法求单源有向图最短路径,djikstra迪杰斯特拉算法(朴素)。

m0_51657509的博客 2696

Mac 不小心断开移动硬盘导致磁盘无法读取和加载(顺利解决!)

Mac移动硬盘不正确断开连接导致无法读取加载的解决方法,亲测有效

Robin_Pi的博客 1万+

Dijkstra实现(邻接表C++版)

Dijkstra实现(邻接表C++版)

ahundredmile的博客 2410

手把手教你学Simulink--基于Simulink的高速公路自动驾驶场景仿真建模

特点车道保持:自动调整车辆方向以保持在车道中央。自适应巡航控制(ACC):根据前方车辆的速度自动调节车速。换道辅助:安全地变换车道以超过慢速行驶的车辆或准备驶离高速公路。紧急制动:检测潜在碰撞并采取措施避免事故。挑战安全性:确保所有功能在各种条件下都能可靠运行。实时性:处理大量传感器数据,并迅速做出反应。复杂性:集成多个子系统,包括感知、规划与控制。首先明确要模拟的任务内容。车辆需保持在车道内行驶。根据交通情况自动调整速度。安全地执行换道操作。在必要时实施紧急制动。

MHD0815的博客 248

YOLOv8融合可变形注意力(DAT)实战教程:暴力涨点的科研级注意力机制优化方案

DAT的“可变形注意力”为目标检测的“精准特征捕捉”提供了全新思路,而YOLOv8的工程化优势让这种科研创新能快速落地到工业场景。希望这篇教程能帮你在“注意力机制优化+复杂场景检测”的痛点上找到突破口。如果你在实操中遇到“涨点不明显”的问题,不妨回到“DAT的采样点是否贴合目标形状”“注意力权重是否有效过滤背景”这些细节上找原因——科研的价值,就在于在细节打磨中推动技术进步。祝你在DAT与YOLOv8的结合探索中,既能做出有说服力的实验成果,又能沉淀出解决异形目标检测难题的实用经验。

know_F0727的博客 88

Dijkstra 算法 C++实现(邻接表)

Dijkstra 用于寻找最短路径。用最短的时间从起点走到终点。

lwasoo的博客 919

《派出你的AI同事:WorkBuddy案例实战》055:客服工单自动分类与话术生成

客服工单自动分类与话术生成 —— 《派出你的AI同事:WorkBuddy案例实战》系列文章,配图已统一为规范示意图。

LuckyHanMo的博客 285

Project Euler Problem 83 (C++和Python代码实现和解析)***

Problem 83 : Path sum: four ways NOTE: This problem is a significantly more challenging version of Problem 81. In the 5 by 5 matrix below, the minimal path sum from the top left to the bottom right, b...

jiafengfu的优快云博客 628

基于MATLAB开发AUTOSAR软件应用层模块-part3.自动生成的代码文件介绍

上篇文章我们介绍了如何设计一个简单的模型,之后自动生成autosar架构的代码,这篇文章我带大家看下,生成了哪些文件,以及这些文件的内容。 生成的文件见下图: model files是模型控制逻辑部分代码,包括 DEMO1.c DEMO1.h DEMO1_private.h DEMO1_types.h DEMO1.c 1 /* 2 * File: DEMO1.c 3 * 4 * Cod.

汽车软件开发 1978

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Project Euler 83

Path sum: two waysProblem 81 In the 5 by 5 matrix below, the minimal path sum from the top left to the bottom right, by only moving to the right and down, is indicated in bold red and is equal to 2427...

weixin_41698125的博客 385

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Project Euler Problem 81

     很显然是一个动态规划的题目,也可以建模为一个有向图,然后用Dijkstra算法寻找最短路径。    具体的实现(C++)可以从右下依次向上做遍历,看到很多人用了递归,纵然不用考虑下标的转换,但效率很低,写的不好让人很不爽。。   Answer:427337 

O(1) 的小乐 566

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

project euler 82

Problem 82 Path sum: three ways NOTE: This problem is a more challenging version of Problem 81. The minimal path sum in the 5 by 5 matrix below, by starting in any cell in the left colu

whuawell的博客 596

project euler 81

Problem 81 Path sum: two ways In the 5 by 5 matrix below, the minimal path sum from the top left to the bottom right, by only moving to the right and down, is indicated in bold red and is eq

whuawell的博客 304

1385 份算法 Python 实现,10 分钟跑通第一个:免费的源码级算法参考库

上次面试官问 Dijkstra 的松弛过程,你只能凭印象复述——课本上的伪代码隔了太久,早就生疏了。其实这个问题不必靠硬背解决。The Algorithms(Python 版)是一个免费的算法 Python 实现合集,仓库里躺着 1400 多份算法源码,从冒泡排序到 Dijkstra、动态规划、机器学习都有,你只需要在本地跑起来,逐行读,就能把任何算法真正搞懂。 ## 它是什么,凭什么放心用

gitblog_00425的博客 949

Project Euler 83:Path sum: four ways 路径和:4个方向

Path sum: four ways NOTE: This problem is a significantly more challenging version ofProblem 81. In the 5 by 5 matrix below, the minimal path sum from the top left to the bottom right, by moving le...

weixin_30348519的博客 88

算法思维:从趣题到实战,掌握问题拆解与算法选型

算法是计算机科学的核心,其本质是一系列解决问题的清晰指令。理解算法原理,关键在于掌握将复杂问题抽象为数学模型,并选择合适策略进行优化的能力。这种算法思维具有极高的技术价值,它不仅是解决LeetCode等编程挑战的基础,更是优化软件性能、设计高效系统的工程实践核心。在实际应用中,从基础的排序与查找,到进阶的搜索、动态规划与贪心策略,都需要根据问题特征精准匹配。例如,面对路径规划可选用A*算法,而处理动态连通性问题则适合并查集。本文以一道虚构的时钟指针重合趣题为引,系统阐述了从问题理解、模型建立到算法选型与编码

weixin_30561177的博客 358

PHP面试逆袭指南:如何用PHP-Data-Structure-and-Algorithms系统刷透数据结构与算法面试题

> PHP 开发者被"问到算法就懵"?开源项目 **PHP-Data-Structure-and-Algorithms** 用纯 PHP 实现了 10 大类、40+ 个数据结构与算法,从链表、栈、队列到图算法、动态规划,全部配可运行的示例代码。跟着它的目录结构刷一遍,数据结构与算法面试题不再难。 ## 🎯 为什么PHP开发者必须啃下数据结构与算法? 面试中,"手写链表反转""二叉树遍历""0

gitblog_01092的博客 263

projecteuler No.83 four ways

题目链接: Problem 83 four ways 题目83:允许向上下左右移动的情况下从左上角到右下角的最小路径和是多少? 通过人数:8961 题目分析: 前面的两道题都用动态规划做了,而这一问缺是典型的单源最短路径问题,我使用了Dijkstra算法。 解题过程(代码仅供参考,因为偷懒,代码风格什么的实在不好意思...): 【原谅我因为偷懒,使用纯c风格写了这

816

PHP数据结构与算法库:如何5分钟上手安装、配置与第一个示例教程

**PHP-Data-Structure-and-Algorithms** 是一个用 PHP 实现主流**数据结构与算法**的开源仓库,涵盖链表、栈、队列、树、堆、图、排序、搜索与动态规划。本教程带你 5 分钟完成**安装配置**,并跑通**第一个 PHP 数据结构示例**。 --- ## 一、环境要求:只需 PHP 7 和 Git 这个项目非常轻量,没有任何第三方依赖,环境准备只需 2 分

gitblog_00887的博客 1258
上一篇: 连分数及Pell方程的解法
下一篇: Project Euler解题汇总 061 ~ 070
JavaSxy
博客等级 码龄21年 1粉丝 25原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值