Advertisement
PearlyXD

Przelewanka

Jan 24th, 2021
4,295
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
OCaml 3.38 KB | None | 0 0
  1. (* autor: Wiktor Chmielewski grupa 5 *)
  2. (* code review: Przemysław Kusiak grupa 5*)
  3.  
  4. type specyfikacja = { v: int array; g: int array };;
  5.  
  6. (* aktualny - aktualne poziomy wody*)
  7. (* pozostaly - liczba szklanek z v.(i) <> g.(i) *)
  8. type stan = { aktualny: int array; pozostaly: int ref };;
  9.  
  10. (* kopia aktualnego stanu *)
  11. let akt_stan st = { aktualny = Array.copy st.aktualny; pozostaly = ref (!(st.pozostaly))};;
  12.  
  13. (* zwraca możliwe stany po zrobieniu operacji w stanie st *)
  14. let dozwolone_stany sp st =
  15.   let n = Array.length st.aktualny
  16.   and zmien_stan sp st i zmiana =
  17.     if st.aktualny.(i) = sp.g.(i) then incr st.pozostaly;
  18.     st.aktualny.(i) <- st.aktualny.(i) + zmiana;
  19.     if st.aktualny.(i) = sp.g.(i) then decr st.pozostaly;
  20.     in
  21.   (* stan, który otrzymamy poprzez wypełnienie i-tej szklanki *)
  22.   let rec wypelnij i lst =
  23.     if i = n then lst
  24.     else
  25.       let roznica = sp.v.(i) - st.aktualny.(i) in
  26.       if roznica = 0 then wypelnij (i + 1) lst
  27.       else
  28.         let nowy_stan = akt_stan st in
  29.         zmien_stan sp nowy_stan i roznica;
  30.         wypelnij (i + 1) (nowy_stan::lst)
  31.   (* stan, który otrzymamy poprzez opróżnienie i-tej szklanki *)
  32.   and oproznij i lst =
  33.     if i = n then lst
  34.     else
  35.       let roznica = - st.aktualny.(i) in
  36.       if roznica = 0 then oproznij (i + 1) lst
  37.       else
  38.         let nowy_stan = akt_stan st in
  39.         zmien_stan sp nowy_stan i roznica;
  40.         oproznij (i + 1) (nowy_stan::lst)
  41.   (* stan, który otrzymamy poprzez przelanie z i-tej szklanki do j-tej szklanki *)
  42.   and przelej i j lst =
  43.     if i = n then lst
  44.     else if j = n then przelej (i + 1) 0 lst
  45.     else if i = j then przelej i (j + 1) lst
  46.     else
  47.       let roznica = min st.aktualny.(i) (sp.v.(j) - st.aktualny.(j)) in
  48.       if roznica = 0 then przelej i (j + 1) lst
  49.       else
  50.         let nowy_stan = akt_stan st in
  51.         zmien_stan sp nowy_stan i (-roznica);
  52.         zmien_stan sp nowy_stan j roznica;
  53.         przelej i (j + 1) (nowy_stan::lst)
  54.   in przelej 0 0 (oproznij 0 (wypelnij 0 []))
  55. ;;
  56.  
  57. let rozwiaz sp st =
  58.   (* rozmiar tablicy hashującej: iloczyn objętości szklanek *)
  59.   let s = Array.fold_left (fun a x -> a * x) 1 sp.v in
  60.   (* tablica odwiedzonych *)
  61.   let odw = Hashtbl.create (max 10000 (min 10000000 s)) in
  62.   let dist = fun v -> (try Hashtbl.find odw v with Not_found -> -1) in
  63.   (* bfs po stanach *)
  64.   let bfs sasiedzi start =
  65.     let q = Queue.create ()
  66.     and cel st = !(st.pozostaly) = 0 in
  67.     let x = ref (cel start)
  68.     and odwiedz = fun v d -> Hashtbl.add odw v d in
  69.     odwiedz start 0;
  70.     Queue.push start q;
  71.     while not (Queue.is_empty q) && not !x do
  72.       let v = Queue.pop q in
  73.       let d = dist v in
  74.       let procesuj u =
  75.         if dist u = -1 then begin
  76.           odwiedz u (d + 1);
  77.           Queue.push u q;
  78.           x := !x || cel u
  79.         end; in
  80.         List.iter procesuj (sasiedzi v)
  81.       done;
  82.   in
  83.   bfs (dozwolone_stany sp) st;
  84.   dist ({aktualny = Array.copy sp.g ; pozostaly = ref 0})
  85. ;;
  86.  
  87. let przelewanka arr =
  88.   let n = Array.length arr in
  89.   (* czytamy specyfikację z arr *)
  90.   let sp = { v = (Array.init n (fun i -> fst arr.(i))); g = (Array.init n (fun i -> snd arr.(i)))} in
  91.   (* stan początkowy - wszystkie szklanki puste *)
  92.   let st = { aktualny = Array.make n 0 ; pozostaly = ref (Array.fold_left (fun a x -> if x = 0 then a - 1 else a) n sp.g)} in
  93.   rozwiaz sp st
  94. ;;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement