用scheme语言实现SPFA算法(单源最短路)

  最近自己陷入了很长时间的学习和思考之中,突然发现好久没有更新博文了,于是便想更新一篇。

  这篇文章是我之前程序设计语言课作业中一段代码,用scheme语言实现单源最段路算法。当时的我,花了一整天时间,学习了scheme并实现了SPFA算法,那天实现之后感觉很有成就感~在这里贴出来,以飨读者。



  突然发现博客园不支持scheme语言,于是只能放弃高亮了。不得不说,scheme代码有没有高亮差别好大……

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;  题目:单源最短路,输入数据给定
;;
;;  作者:卢奇
;;  学号:5130309680
;;  邮箱:[email protected]
;;
;;  算法:SPFA(简化版)
;;
;;  代码结构:共三大部分——
;;    开始是一些语法糖,
;;    然后是SPFA算法的实现,
;;    最后是主体部分,调用了SPFA算法并输出结果。
;;
;;  备注:代码备注共有两种——
;;    1. 代码的三大部分,各自开头有一段备注
;;    2. 代码的两个主体部分,内部穿插了一些备注
;;      其中,两个主体部分是指:代码主体部分 以及 SPFA算法的主体部分(即SPFA函数)
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(begin

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;;
  ;;  这里是为后面代码定义的一些语法糖。
  ;;
  ;;  为了可读性,我做了一个“下标变换”:
  ;;    题目图中6个点,存储为0~5,但供操作的API对外设计成1~6的假象,简化思路
  ;;
  ;;  有一维数组、二维数组、队列和逻辑运算几方面,具体如下所示:
  ;;    1. 根据下标该值,构造新数组:change, change2
  ;;    2. 根据下标赋值(+下标变换):set, set2
  ;;    3. 根据下标取值(+下标变换):get, get2
  ;;    4. 入队、出队:push, pop
  ;;    5. 逻辑运算(二元与、二元或):and, or
  ;;
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  (define (change a i x)
    (if (eqv? i 0)
	(cons x (cdr a))
	(cons (car a) (change (cdr a) (- i 1) x))))
  (define (change2 a i j x)
    (if (eqv? i 0)
	(cons (change (car a) j x) (cdr a))
	(cons (car a) (change2 (cdr a) (- i 1) j x))))
  (define-syntax set
    (syntax-rules ()
      ([set a i x] (set! a (change a (- i 1) x)))))
  (define-syntax set2
    (syntax-rules ()
      ([set2 a i j x]
       (begin
	 (set! a (change2 a (- i 1) (- j 1) x))
	 (set! a (change2 a (- j 1) (- i 1) x))))))
  (define-syntax get
    (syntax-rules ()
      ([get a i] (list-ref a (- i 1)))))
  (define-syntax get2
    (syntax-rules ()
      ([get2 a i j] (list-ref (list-ref a (- i 1)) (- j 1)))))

  (define-syntax push
    (syntax-rules ()
      ([push Q x] (set! Q (append Q (list x))))))
  (define-syntax pop
    (syntax-rules ()
      ([pop Q]
       (let ([x (car Q)])
	 (set! Q (cdr Q))
	 x))))

  (define-syntax and
    (syntax-rules ()
      ([and Ea Eb]
       (if (eqv? Ea #t)
	   (if (eqv? Eb #t) #t #f)
	   #f))))
  (define-syntax or
    (syntax-rules ()
      ([or Ea Eb]
       (if (eqv? Ea #t)
	   #t
	   (if (eqv? Eb #t) #t #f)))))

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;;
  ;;  此为SPFA算法部分(简化版)
  ;;
  ;;  其中SPFA函数是主体,其调用了update-all函数,后者又调用了update函数。
  ;;
  ;;  注:之所以称之为简化版,是因为本来SPFA的入队应该去重的,但被我给省了。
  ;;     不过本题中并不要求速度、也不影响正确性,写不写也就无所谓了。
  ;;
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  (define (update map d Q u allv)
    (cond
     [(not (eqv? allv null))
      (let ([v (car allv)] [lastv (cdr allv)])
;	(newline)
;	(display "an update --") (newline)
;	(display "d: ") (display d) (newline)
;	(display "Q: ") (display Q) (newline)
;	(display "u: ") (display u) (newline)
;	(display "v: ") (display v) (newline)
;	(display "allv: ") (display allv) (newline)
	(cond
	 [(and (not (eqv? (get2 map u v) #f)) (or (eqv? (get d v) #f) (< (+ (get d u) (get2 map u v)) (get d v))))
	  (begin
	    (set d v (+ (get d u) (get2 map u v)))
	    (push Q v))])
	(update map d Q u lastv))]
     [else (list d Q)]))

  (define (update-all map d Q)
    (if (eqv? Q null)
	d
	(let ([u (pop Q)])
	  (define tmp  (update map d Q u (list 1 2 3 4 5 6)))
	  (set! d (car tmp))
	  (set! Q (cadr tmp))
	  (update-all map d Q))))

  (define (SPFA map s)
					; 初始化SPFA中的数组
    (define d (make-list 6 #f))
    (set d s 0)
    (define Q null)
    (push Q s)
					; 输出初始化的数组,仅供调试
    (display "d: ") (display d) (newline)
    (display "Q: ") (display Q) (newline)
					; 计算由s出发的单源最短路,并返回计算出的结果
    (update-all map d Q))

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;;
  ;;  题目主函数在此
  ;;
  ;;  本题所有的IO都在这里给出了,一目了然。
  ;;
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

					; 建图 称为map
  (define map (make-list 6 (make-list 6 #f)))
  (set2 map 1 2 7)
  (set2 map 1 3 9)
  (set2 map 1 6 14)
  (set2 map 2 4 15)
  (set2 map 2 3 10)
  (set2 map 3 4 11)
  (set2 map 3 6 2)
  (set2 map 4 5 6)
  (set2 map 5 6 9)
					; 通过简化的SPFA算法计算最短路
  (define d (SPFA map 1))
					; 输出答案
  (display "last-d: ") (display d) (newline)
  (display "result: ") (display (get d 5)) (newline))
时间: 2024-10-05 22:17:07

用scheme语言实现SPFA算法(单源最短路)的相关文章

POJ2253&amp;ZOJ1942--Frogger【SPFA】单源最短路变形

链接:http://poj.org/problem?id=2253 题意:一个青蛙在一块石头上,看到了另一个青蛙在另一块石头上,它想跳过去找它,如果距离太远它就需要借助别的石头当跳板,两块石头之间的青蛙距离被定义成两块石头之间所有路径中最大跳跃距离的最小值,求两个青蛙之间的青蛙距离. poj2263和它类似,链接:http://poj.org/problem?id=2263 解题报告:Here 这是最短路的变形,每两点之间都有路可以跳,更新最短路的值,权值记录成目前到这一点的最小青蛙距离就行了

SPFA算法-单源最短路径算法

1.介绍: SPFA算法:单源最短路径算法,一种高效的最短路径算法! 2.思路 (1)初始化 1>源点路径为0  :d[s]=0 ,其中s为源点 2>初始化d[N]为无穷大,即d[i]表示,源点s到i为无穷大INF 3>p[N]初始化为源点s或-1,表示没有前驱 (2)队列+松弛 1>读取队头顶点u,并将队头顶点u出队(记得消除标记): 2>将与点u相连的所有点v进行松弛操作,如果能更新估计值(即令d[v]变小),那么就更新; 3>另外,如果点v没有在队列中,那么要将点

Dijkstra算法 --- 单源最短路

Dijkstra算法适用于边权值为正的情况,可用于计算正权图上的单元最短路. 其伪代码如下: 设d[v0] = 0, 其他d[i] = INF 循环n次{ 在所有未标号的结点中,选取d值最小的结点x 给结点x加上永久标号 对于从x出发的所有边,执行松弛操作. } //松弛操作的伪代码如下: RELAX(u,v,w) if(u.d + w(u,v) < v.d){ v.d = w.d + w(u,v); pre[v] = u; } Dijkstra算法代码: /* Dijkstra 单源最短路算法

模板C++ 03图论算法 1最短路之单源最短路(SPFA)

3.1最短路之单源最短路(SPFA) 松弛:常听人说松弛,一直不懂,后来明白其实就是更新某点到源点最短距离. 邻接表:表示与一个点联通的所有路. 如果从一个点沿着某条路径出发,又回到了自己,而且所经过的边上的权和小于0, 就说这条路是一个负权回路. 回归正题,SPFA是bellman-ford的一种改进算法,由1994年西安交通大学段凡丁提出.它无法处理带有负环的图,判断方法:如果某个点进入队列的次数超过N次则存在负环. SPFA的两种写法,bfs和dfs,bfs判别负环不稳定,相当于限深度搜索

再看最短路算法 1 —— 单源最短路

学了多年的算法,最短路问题相当之常见———— 好久没写过最短路的问题了,直到昨天闲的无聊来了一题——BZOJ3402(HansBug:额才发现我弱到只能刷水的地步了TT) 一看这不是明显的单源最短路么呵呵...于是直接上来来了个dijkstra,而且用的是邻接表存储图—— Submit之后,结果却是—— 我立刻被雷到了QAQ...于是立刻改写spfa,结果—— 4000ms+(估计还不止)和192ms究竟是怎样的差距啊QAQ,本人虽然早都听说过spfa的强大性,但是未曾想过差距会如此可怕,于是H

【裸单源最短路:Dijkstra算法两种版本】hdu 1874 畅通工程续

Source : hdu 1874 畅通工程续 http://acm.hdu.edu.cn/showproblem.php?pid=1874 Problem Description 某省自从实行了很多年的畅通工程计划后,终于修建了很多路.不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行走的距离要短很多.这让行人很困扰. 现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离. Input 本题目包含多组数据,请处理到文件结束.

编程算法 - 单源最短路问题 Bellman-Ford 代码(C)

单源最短路问题 Bellman-Ford 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 单源最短路: 固定一个起点, 求它到其他所有点的最短路的问题. Bellman-Ford: 设当前到顶点i的最短路长度为d[i], 并设初值d[s]=0, d[i]=INF, 再不断使用递推关系式d[e.to] = d[e.from] + e.cost更新d的值. 时间复杂度: O(V*E) 代码: /* * CppPrimer.cpp * * Created

uva 10099 The Tourist Guide(单源最短路/spfa/dijkstra)

题目: 链接:点击打开链接 题意: 思路: 代码: #include <iostream> #include <cstring> #include <cstdio> using namespace std; int map[101][101]; void floyd(int n) { for(int k=1; k<=n; k++) for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) map[i][j] = m

利用无权图的单源最短路算法实现地铁换乘图

//Metro.php $MetroVertex = array( 1 => '体育中心', 2 => '体育西路', 3 => '杨箕', 4 => '东山口', 5 => '烈士陵园', 6 => '农讲所', 7 => '公园前', 8 => '西门口', 9 => '陈家祠', 10 => '长寿路', 11 => '黄沙', 12 => '芳村', 13 => '花地湾', 14 => '坑口', 15 =>