Ocaml:加权图

时间:2015-08-29 06:59:39

标签: graph ocaml

我正在研究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 :(节点开始 - 边缘 - 节点到达):

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解决最长的路径问题(给定一个起始节点和一个停止节点,如果存在节点之间的路径,则说明为true一个最小权重k)我必须在我的函数上实现(x,y,z)格式,所以我尝试了这样的事情:(与你建议的功能相同,但用(x,y,z)代替n:< / p>

    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];;

1 个答案:

答案 0 :(得分: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函数也应该如此。但是在这里,您出于某种原因,决定将{@ 1}}列表中的边缘存储起来,并使用您自己的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] 的值。