【问题标题】:Ocaml - Path between two nodes (How to debug)Ocaml - 两个节点之间的路径(如何调试)
【发布时间】:2015-11-29 06:38:21
【问题描述】:

我需要制定一个算法来使用 BFS 解决这个问题: 给定一个有向加权图、一个起始节点、一个终止节点和一个整数 K,假设在起始和终止之间是否存在一条 wight 至少为 k 的路径。

所以,首先我声明了我的加权导向图类型,一个三元组列表:

 type 'a graph = Gr of ('a * 'a * 'a) list;;

 let grafo1 =  Gr [(1,3,2);(1,1,5);(2,2,3);(5,5,3);(5,4,6);(3,1,6);(3,7,4);(6,2,7);(4,4,6)];;

(x,y,z)中,x是起始节点,y是边权重,z是到达节点。

然后我做了一个succ函数:

let succ (Gr arcs) n=
     let rec aux = function
         [] -> []
         | (x,y,z):: rest ->
           if n = x then z::(aux rest)
           else aux rest 
    in aux arcs;;

这个函数给我一个节点的后继作为输出,所以:

succ grafo1 1 

给我

   int list = [2; 5]

作为输出。

最后,我做了这个 bf_path 函数,它是一个修改后的 BFS,可以找到 2 个节点之间的路径(否则会引发异常),它需要 3 个输入:一个图形,谓词和起始节点

 let bf_path g p start =  
       let rec aux visited = function  
           [] -> raise Not_found  
           | x::rest -> if List.mem x visited then aux visited rest  
              else if p x then [x]  
              else try aux (x::visited) rest  
                with Not_found ->  
                  x:: aux (x::visited) (succ g x)  
       in aux [] [start];; 

谓词指定条件,所以调用:

  bf_path grafo1 ((=)7)1

给我int list = [1; 5; 6; 7] 作为输出,节点 1 和 7 之间的路径。

现在,我可以找到一条路径,但我需要找到一条 至少 权重 K 的路径,所以我做了一个小函数,它以三元组列表作为输入并将其相加重量值:

let rec tot = function
   [] -> 0
   |(v,c,p)::t -> c + (tot t);;

所以,调用并输出:

  tot [(2,2,3);(4,5,6);(8,9,0)]

   - : int = 16

我认为我需要的只是在函数中添加条件,所以我创建了这个函数,我添加了一个 int K 作为输入和一个条件:(tot path >= k)

   let bf_path_final g p start k =  
      let rec aux visited = function  
        [] -> raise Not_found  
        | x::rest -> if List.mem x visited then aux visited rest  
            else if p x then 
               if (tot [x]) >= k then [x]
               else aux visited rest 
            else try aux (x::visited) rest  
              with Not_found ->  
                x:: aux (x::visited) (succ g x)  
      in aux [] [start];; 

函数编译没有问题:

   val bf_path_final : ('a * int * 'b) graph -> 
  ('a * int * 'b -> bool) -> 'a * int * 'b -> int -> ('a * int * 'b) list = <fun>

但是,当我尝试调用它时收到 错误

bf_path_final grafo1 ((=)4)1,13;;
              ^^^^^^
Error: This expression has type int graph_w
       but an expression was expected of type ('a * int * 'b) graph_w

那么,是函数错误还是我必须以其他方式调用它?

另一种解决方案是将函数 bf_path 输出(路径)作为我的 tot 函数的输入,但我的输出是一个列表int,而不是三元组列表,所以我尝试将我的第一个函数转换为三元组的输出:

(例如:而不是[1;5;6;7],它应该给出[(1,1,5);(5,4,6);(6,2,7)]

let bf_path_tr g p start =  
    let rec aux visited = function  
         [] -> raise Not_found  
         | (x,y,z)::rest -> if List.mem x visited then aux visited rest  
            else if p x then [(x,y,z)]  
            else try aux (x::visited) rest  
              with Not_found ->  
                 (x,y,z):: aux (x::visited) (succ_w g (x,y,z))  
    in aux [] [start];; 

同样的结果,函数编译完成

 val bf_path_tr :
  ('a * 'b * 'c) graph ->
  ('a -> bool) -> 'a * 'b * 'c -> ('a * 'b * 'c) list = <fun>

但我得到同样的错误:

bf_path_tr grafo1 ((=)7)2

  Characters 11-18:
  bf_path_tr grafo1 ((=)7)2;;
             ^^^^^^
  Error: This expression has type int graph
     but an expression was expected of type ('a * 'b * 'c) graph

有什么想法可以解决这两个问题中的至少一个吗?

【问题讨论】:

    标签: graph path ocaml


    【解决方案1】:

    调试此类事情的最佳方法是开始在各处添加显式类型注释,直到找到您的期望与推断类型不匹配的地方。

    let bf_path_final (g : int graph) (p : int -> bool) (start : int) (k : int) =   
      let rec aux (visited : int list) = function  
          [] -> raise Not_found  
        | x::rest -> if List.mem x visited then aux visited rest  
          else if p x then ( 
            if (tot [x]) >= k then [x] 
            else aux visited rest )
          else try aux (x::visited) rest  
            with Not_found ->  
              x:: aux (x::visited) (succ g x)  
      in aux [] [start];; 
    

    引发错误

    File "test.ml", line 32, characters 17-18:
    Error: This expression has type int but an expression was expected of type
             'a * int * 'b
    

    它指向if (tot [x]),其中tot 确实需要一个三元组列表,但您已将它传递给一个int 列表。

    你真的是想打电话给tot [x]吗?它没有总计任何东西; x 只是那里的一个节点。

    【讨论】:

    • 我尝试去 backt 解决问题,所以我修改了第一个 bf_patg 函数以适应三元组,因此函数 tot 将正常工作。 (我更新了问题)。
    • 您是否尝试向所有内容添加类型注释?这仍然可以帮助您找出问题所在
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-04
    相关资源
    最近更新 更多