Se il problema è abbastanza piccolo, un approccio totalmente ingenuo funziona bene. Vogliamo generare tutti i percorsi hamiltoniani bloccati che connettono due nodi a e b in un dato grafico . Per questo, generiamo solo tutti i percorsi validi provenienti da a e filtriamo quelli che non sono hamiltoniani o che non terminano in b .
Il seguente snippet di codice è un'implementazione di questa idea in OCaml. Sulla mia macchina può trovare tutto il percorso hamiltoniano riposto in un grafico completo di dimensione 9 (ci sono (9-2)! = 5040 tali percorsi, sono tutte le permutazioni di 7 nodi non appuntati), ma il programma non può gestire il caso della dimensione 10. Questo dovrebbe darti un'idea della complessità dell'operazione, ma come puoi vedere, non potrei essere meno ingenuo quando implemento questo.
module Graph =
struct
type t = {
node: int list;
edge: (int * int list) list;
}
let nodes graph =
List.sort_uniq Pervasives.compare graph.node
let neighbours graph n =
try List.assoc n graph.edge
with Not_found -> []
let pointed_hamiltonian_paths graph a =
let is_visiting_all_nodes path =
let sort = List.sort Pervasives.compare in
sort path = sort graph.node
in
let hamiltonian_extensions path =
match path with
| [] -> []
| node :: _ ->
match List.filter
(fun x -> not(List.mem x path))
(neighbours graph node)
with
| [] -> [ path ]
| newnodes -> List.map (fun x -> x :: path) newnodes
in
let rec loop paths =
match List.concat (List.map hamiltonian_extensions paths) with
| [] -> []
| newpaths ->
if newpaths = paths then paths else loop newpaths
in
List.filter is_visiting_all_nodes (loop [[a]])
let pinned_hamiltonian_paths graph a b =
List.filter (fun path -> (match path with hd ::_ -> hd = b | [] -> false))
(pointed_hamiltonian_paths graph a)
let example_1 = {
node = [1; 2; 3; 4; 5];
edge = [
1, [ 4 ];
2, [ 4; 5];
3, [ 5 ];
4, [ 1; 2; 5 ];
5, [ 2; 3; 4 ];
];
}
let example_2 = {
node = [ 6; 7; 8 ];
edge = [
6, [ 7; 8];
7, [ 6; 8];
8, [ 6; 7];
];
}
let example_3 = {
node = example_1.node @ example_2.node;
edge = example_1.edge @ example_2.edge;
}
let complete n =
let rec loop ax i =
if i < 1 then ax else loop (i :: ax) (pred i)
in
let seq = loop [] n in {
node = seq;
edge = List.map (fun x -> x, seq) seq;
}
end
Ci sono tre esempi di grafici definiti, il primo è:
il secondo è un grafico completo senza loop (i bordi hanno lo stesso punto iniziale e finale) e il terzo è l'unione disgiunta dei due. Con queste definizioni possiamo sperimentare un po 'in alto:
# Graph.pinned_hamiltonian_paths Graph.example_1 1 3;;
- : int list list = [[3; 5; 2; 4; 1]]
# Graph.pinned_hamiltonian_paths Graph.example_2 6 8;;
- : int list list = [[8; 7; 6]]
# Graph.pinned_hamiltonian_paths Graph.example_3 1 3;;
- : int list list = [] (* The graph is not connected! :) *)
# Graph.pinned_hamiltonian_paths (Graph.complete 4) 1 4;;
- : int list list = [[4; 3; 2; 1]; [4; 2; 3; 1]]