【问题标题】:Ocaml: weighted graphOcaml:加权图
【发布时间】:2015-08-29 06:59:38
【问题描述】:

我正在研究 Ocaml,但我还是个初学者,所以我必须寻求一些帮助。
按照书上的说明,我创建了一个表示有向图的类型:

type 'a graph = Gr of ('a * 'a) list;;
let grafo1 = Gr [(1,2);(1,3);(1,4);(2,6);(3,5);(4,6);(6,5);(6,7);(5,4)];;

然后我创建了一个以节点为输入的 succ 函数,它给我他的继任者作为输出:

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

然后我用 succ 函数做了一个修改后的 BFS 函数,这个函数告诉我是否存在 2 个节点之间的路径:

let bfs graph p start =
  let rec search visited = function
         [] -> raise Nodo_not_reachable
     |n:: rest ->
           if List.mem n visited
           then search visited rest
           else if p n then n
           else search (n::visited) (rest @ (succ graph n))
  in search [] [start];;

我使用以下代码调用函数:

bfs grafo1 (function x -> x=7) 1;;

如果节点 1 和节点 7 之间存在路径,则函数将输出 true。 现在,我想做同样的事情,但使用加权图,所以我创建了一个新类型,一个列表,其中每个元素由 3 个数字而不是 2 个数字组成:(节点开始 - 边缘的 wiegh - 节点到达):

type 'b graph_w = Grw of ('b * 'b * 'b) list;;

let grafo2 =  Grw [(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)];;

所以,我修改了我之前的函数以适应这种类型:

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

let bfs_w graph_w p start =
       let rec search visited = function
            [] -> raise Nodo_non_raggiungibile
       |n:: rest ->
         if find n visited
         then search visited rest
         else if p n then n
         else search (n::visited) (rest @ (succ_w graph_w n))
      in search [] [start];;

(因为我不能在这种新类型上使用 List.mem,所以我声明了一个名为 find 的函数,如果元素 (x,y,z) 包含在列表中,则输出为 true):

let rec find (x,y,z) = function
    [] -> false
  | (v,c,p)::rest -> if (x=v) then true else find (x,y,z) rest;;

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

现在有个小问题,谁能告诉我如何使用新的图形类型调用我的 bfs_w 函数?
使用

 bfs_w grafo2 (function x -> x=7) 1;;

我收到以下错误:

This expression has type int graph_w but an expression was expected of type ('a * 'b * 'c) graph_w

/--------------------------------/

好的,现在函数可以正常工作了 thx ^^,但是还有另一个问题:因为我想使用 bfs 解决最长路径问题(给定一个开始节点和一个停止节点,如果节点之间存在路径最小权重 k) 我必须在我的函数上实现 (x,y,z) 格式,所以我尝试了这样的方法:(与您建议的函数相同,但使用 (x,y,z) 代替 n:

    let bfs_w2 graph_w start stop =
       let rec search visited = function
         | [] -> raise Node_not_Reachable
         | (v,c,p) :: rest ->
              if (find (v,c,p) visited) then search visited rest 
               else if v = stop then true
              else search ((v,c,p)::visited) (rest @ (succ_w graph_w    (v,c,p))) in
         search [] [start];;

当我声明函数时:

     bfs_w2 grafo2 1 4;;

     bfs_w2 grafo2 (function x -> x=4) 1;;

我在“grafo2”上遇到了同样的错误:

        This expression has type int graph_w

但表达式应为 ('a * 'b * 'c) graph_w 类型

我不明白问题出在哪里,功能与您建议的几乎相同。

ps:我什至试过这个,但我遇到了同样的结果:

      let bfs_w2 graph_w p start  =
          let rec search visited = function
             | [] -> raise Nodo_not_reachable
             | (x,y,z) :: rest ->
                 if (List.mem (x,y,z) visited) then search visited rest 
                 else if p (x,y,z) then (x,y,z) 
                 else search ((x,y,z)::visited) (rest @ (succ_w graph_w (x,y,z))) in
         search [] [start];;

【问题讨论】:

    标签: graph ocaml


    【解决方案1】:

    首先让我定义你的图形模型,这样我们就可以说同一种语言。您正在使用边列表来表示图形。对于'a graph 类型的图,我们会说'anode,而'a * 'a = node * node 是一条边。所以图形本身表示为edge list。要表示加权图,您使用带有权重标记的边,因此 edge 现在具有类型 node * weight * node,其中 weight 具有类型 int

    现在,让我们来解决您的问题。如果您仔细查看bfs 的实现,您会注意到visited 的类型为node list(即int list),而不是edge list。而且您将谓词应用于node 类型的值,而不是边缘。 bfs_w 函数也应该如此。但是在这里,出于某种原因,您决定将边存储在visited 列表中,并使用您自己的find 函数,而不是在这里完全适用的List.mem

    let bfs_w graph_w p start =
      let rec search visited = function
        | [] -> raise Not_found
        | n :: rest ->
          if List.mem n visited
          then search visited rest
          else if p n then n
          else search (n::visited) (rest @ (succ_w graph_w n)) in
      search [] [start]
    

    此实现将具有正确的类型,期望用户谓词接受 node 类型的值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多