(**************************************************************************)
(* *)
(* Thibaut Balabonski, Sylvain Conchon, Jean-Christophe Filliâtre, *)
(* Kim Nguyen, Laurent Sartre *)
(* *)
(* Informatique - MP2I/MPI - CPGE 1re et 2e années. *)
(* Cours et exercices corrigés. Éditions Ellipses, 2022. *)
(* *)
(* https://www.informatique-mpi.fr/ *)
(* *)
(**************************************************************************)
(* Graphes orientés, par listes d'adjacence *)
type digraph = int list array
let create (n: int) : digraph =
Array.make n []
let size (g: digraph) : int =
Array.length g
let has_edge (g: digraph) (u: int) (v: int) : bool =
List.mem v g.(u)
let add_edge (g: digraph) (u: int) (v: int) : unit =
if not (has_edge g u v) then
g.(u) <- v :: g.(u)
let succ (g: digraph) (u: int) : int list =
g.(u)
type edge = int * int
let edges (g: digraph) : (int * int) list =
let l = ref [] in
for i = 0 to size g - 1 do
List.iter (fun j -> l := (i, j) :: !l) g.(i)
done;
!l
let mirror g =
let m = create (size g) in
for i = 0 to size g - 1 do
List.iter (fun j -> add_edge m j i) g.(i)
done;
m
let dfs (g: digraph) (source: int) : bool array =
let visited = Array.make (size g) false in
let rec dfs v =
if not visited.(v) then (
visited.(v) <- true;
List.iter dfs (succ g v);
) in
dfs source;
visited
let exists_path g u v =
(dfs g u).(v)
module Stack = Istack (* nos piles *)
(* Parcours en profondeur sans utiliser de récursivité.
On utilise une pile contenant des paires (sommet v, liste de
voisins de v restant à traiter).
Temps O(E+V) espace O(V) comme pour la version récursive.
L'espace est O(V) car chaque sommet n'est mis qu'au plus une fois
dans la pile, et les listes de voisins ne sont que des pointeurs
dans des listes qui existent déjà. *)
let dfs_stack (g: digraph) (source: int) : bool array =
let visited = Array.make (size g) false in
let st = Stack.create () in
let add v = if not visited.(v) then ( (* pré-traitement de v ici *)
visited.(v) <- true; Stack.push st (v, succ g v)) in
add source;
while not (Stack.is_empty st) do
match Stack.pop st with
| v, [] -> () (* post-traitement de v ici *)
| v, w :: sv -> Stack.push st (v, sv); add w
done;
visited
let dfs_path (g: digraph) (source: int) : int array =
let visited = Array.make (size g) false in
let path = Array.make (size g) (-1) in
let rec dfs p v =
if not visited.(v) then (
visited.(v) <- true;
path.(v) <- p;
List.iter (dfs v) (succ g v);
) in
dfs source source;
path
let rec build_path path acc v =
if path.(v) = -1 then raise Not_found;
if path.(v) = v then v :: acc
else build_path path (v :: acc) path.(v)
let path g u v =
let path = dfs_path g u in
build_path path [] v
type color = Unvisited | InProgress | Visited
let has_cycle g source : bool =
let color = Array.make (size g) Unvisited in
let rec dfs v = match color.(v) with
| Visited -> ()
| InProgress -> raise Exit
| Unvisited ->
color.(v) <- InProgress;
List.iter dfs (succ g v);
color.(v) <- Visited
in
try dfs source; false with Exit -> true
module Queue = Iqueue (* nos files *)
let bfs (g: digraph) (source: int) : int array =
let dist = Array.make (size g) max_int in
dist.(source) <- 0;
let q = Queue.create () in
Queue.enqueue q source;
while not (Queue.is_empty q) do
let v = Queue.dequeue q in
let d = dist.(v) in
List.iter
(fun w -> if dist.(w) = max_int then (
dist.(w) <- d + 1;
Queue.enqueue q w)
)
(succ g v)
done;
dist
let post_order (g: digraph) : int list =
let visited = Array.make (size g) false in
let order = ref [] in
let rec dfs v =
if not visited.(v) then (
visited.(v) <- true;
List.iter dfs (succ g v);
order := v :: !order
) in
for v = 0 to size g - 1 do dfs v done;
!order
let matrix g =
let n = size g in
let m = Array.make_matrix n n 0 in
let add i l = List.iter (fun j -> m.(i).(j) <- 1) l in
Array.iteri add g;
m
open Scanf
let load file =
let c = Scanning.open_in file in
let n = bscanf c "%d\n" (fun n -> n) in
let g = create n in
let e = bscanf c "%d\n" (fun e -> e) in
for _ = 1 to e do bscanf c "%d %d\n" (add_edge g) done;
g
open Format
let print fmt g =
let n = size g in
fprintf fmt "%d@\n" n;
let e = Array.fold_left (List.fold_left (fun e _ -> e+1)) 0 g in
fprintf fmt "%d@\n" e;
for i = 0 to n - 1 do
List.iter (fun j -> fprintf fmt "%d %d@\n" i j) g.(i)
done
(* quelques graphes particuliers *)
let cycle n =
let g = create n in
for i = 0 to n-1 do add_edge g i ((i+1) mod n) done;
g
let full ?(loop=false) n =
let g = create n in
for i = 0 to n-1 do
for j = 0 to n-1 do
if i <> j || loop then add_edge g i j
done
done;
g
(* grille n*m où le sommet (i,j) est l'entier i*m+j,
avec des arcs vers la droite et vers le bas *)
let grid n m =
let g = create (n * m) in
let v i j = i * m + j in
for i = 0 to n-1 do
for j = 0 to m-1 do
if j < m-1 then add_edge g (v i j) (v i (j+1));
if i < n-1 then add_edge g (v i j) (v (i+1) j)
done
done;
g