Ocaml: самый длинный путь с использованием BFS - PullRequest
1 голос
/ 15 января 2020

Проблема заключается в следующем: учитывая ориентированный взвешенный граф, начальный узел, конечный узел и число k, проверьте, существует ли путь от начального узла до конечного узла по крайней мере длиной k.
Это это код, который я написал, и это правильно, но только в указанном c графике. Например, g1 с weights1 выглядит следующим образом: enter image description here

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

let f1 = function
1 -> [5]
| 2 -> [1;3;4]
| 3 -> [6]
| 4 -> [3]
| 5 -> [2;6]
| 6 -> [7]
| _ -> [];;

type 'a graph = Graph of ('a -> 'a list);;
let g1 = Graph f1;;

let weights2 = [(1,3,2);(1,9,5);(2,2,3);(5,4,6);(3,1,6);(3,7,4);(6,2,7);(4,4,6);(6,1,2)];;

let f2 = function
1 -> [2;5]
| 2 -> [3]
| 3 -> [4;6]
| 4 -> [6]
| 5 -> [6]
| 6 -> [2;7]
| _ -> [];;

let g2 = Graph f2;; 


exception NotFound;;
exception Errore;;


(* Function that return the weight of an edge given 2 nodes*)
let rec get_k x y = function
    [] -> 0
    |(a,b,c)::rest -> if((a=x && c=y))then b else get_k x y rest;;


(* Function that calculate the total cost of a given path*)
let cost_of_path path weight = 
    let rec sum cost = function
        []->raise Errore
        |x::y::rest -> sum (cost + get_k x y weight) (y::rest)
        |_::[]->cost 
in sum 0 path;;

(*this function print the list of the path*)
let rec printList = function [] -> print_newline()
    | x::rest -> print_int(x); print_string("; "); printList rest;;

(* Simple bfs function, return only 1 path that connect the start node to the final node*)
let bfs start last_node (Graph succ) =
    let extends path = printList path;
        List.map (function x -> x::path) (List.filter (function x -> not (List.mem x path)) (succ (List.hd path)))
        in let rec aux last_node = function
            [] -> raise Not_found 
            | path::rest -> 
                if (last_node = List.hd path) then List.rev path
                else aux last_node (rest @ (extends path))                     
in aux last_node [[start]];; 


let loghest_path start final_node k weight (Graph succ)=
    let extends path = printList path;
        List.map (function x -> x::path)(succ (List.hd path))    
        in let rec aux final_node = function
            [] -> raise NotFound 
            | path::rest -> 
                (*if the cost of this path is >= k and the last node is the final node, return that path.*)
                if ((cost_of_path (List.rev path) weight >= k) && (List.hd path == final_node)) then List.rev path 

                (*HERE IS THE ERROR: if the total weight of the singole path is >= k but the last node is not the final node,
                find a path that connect the last node of this path to the final node using bfs. It can happen that the path exists
                but it return "Not_Found".*)
                else if((cost_of_path (List.rev path) weight) >= k)
                then (List.rev (List.tl path)) @ bfs (List.hd path) (final_node) (Graph succ)

                (* If the weight is not yet k than extend the path and try another one in list 'rest' *)
                else aux final_node (rest @ (extends path))
in aux final_node [[start]];;


(*Function that calls the other function 'loghest_path' and print the result *)
let find_path start final_node k weigths (Graph succ)=
    let result = (loghest_path start final_node k weigths (Graph succ)) in 
    print_string("Final Path:"); printList result ;
    print_string("The weight is:"); print_int (cost_of_path result weigths); print_newline();;

И выполнение моего кода с использованием весов1 и g1: enter image description here

Теперь, если я выполню свой код в другом графике, например:

let weights3 =[(1,1,2);(1,1,3);(1,1,4);(2,1,5);(2,1,6);(3,1,7);(3,1,8);(4,1,9);(4,1,10);(10,1,1)];;
let f3 = function
1 -> [2;3;4]
| 2 -> [5;6]
| 3 -> [7;8]
| 4 -> [9;10]
| 10 -> [1]
| _ -> [];;
let g3 = Graph f3;;

enter image description here

При следующем выполнении Мой код завершается ошибкой: enter image description here

Это потому, что последний путь перед поиском пути, который по крайней мере k, начинается с узла 2, и нет пути, который может соединить 2 с 10, но путь от 1 до 10 весов 10 существует, и он не был выбран. Может кто-нибудь объяснить мне, как я могу изменить свой код, чтобы убедиться, что проблема решена в каждом типе графика?

1 Ответ

1 голос
/ 15 января 2020

Как вы сами заявили, блок

    else if((cost_of_path (List.rev path) weight) >= k)
    then (List.rev (List.tl path)) @ bfs (List.hd path) (final_node) (Graph succ)

может потерпеть неудачу, поскольку ничто не гарантирует существование пути от последнего элемента текущего пути к конечному узлу.

Самый простой способ - просто удалить этот блок и ... вот и все.

Нет необходимости менять алгоритмы, когда один частичный путь превышает пороговое значение длины (и это не тот алгоритм, который нужно пытаться оптимизируют).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...