Advertisement
martinmazur

Przelewanka

Jan 20th, 2020
1,458
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
OCaml 6.30 KB | None | 0 0
  1. (* Przelewanka
  2. Recenzent: Piotr Prabucki
  3. Autor: Marcin Mazur *)
  4.  
  5. (* Exception, ktore konczy program, jesli znajdzie odpowiedz *)
  6. exception Koniec of int
  7.  
  8. let przelewanka int_array =
  9.  
  10. (* Array bez kubków zer, poniewaz nie wplywaja one na rozwiazanie *)
  11.     let good_input_array =
  12.         Array.of_list (List.filter (fun (x, _) -> if x = 0 then false else true) (Array.to_list int_array)) in
  13.  
  14. (* Dlugosc naszej tablicy *)
  15.     let dlugosc = Array.length good_input_array in
  16.  
  17. (* Pojemnosci szklanek *)
  18.     let pojemnosci = Array.map (fun (y, _) -> y) good_input_array in
  19.  
  20. (* Licze NWD pojemnosci kubkow *)
  21.     let nwd =
  22.         let rec nwd_licz x y =
  23.             if x = 0 then y
  24.             else nwd_licz (y mod x) x in
  25.         Array.fold_left nwd_licz 0 pojemnosci in
  26.  
  27. (* Czy to nie jest juz odpowiedz*)
  28.     if Array.for_all (fun (_, y) -> y = 0) good_input_array || dlugosc = 0 then 0
  29.  
  30. (* Sprawdzam czy istnieje kubek, ktoy trzeba napelnic do pelna lub
  31.     kubek, ktorego nie trzeba napelniac *)
  32.     else if Array.for_all (fun (x, y) -> x <> y && y <> 0) good_input_array then -1
  33.  
  34. (* Sprawdzam czy wszystkie stany koncowe sa podzielne przez NWD *)
  35.     else if not (Array.for_all (fun (_, x) -> (x mod nwd) = 0) good_input_array) then  -1
  36.  
  37. (* Tutaj zaczyna sie implementacja i wyliczanie stanow*)
  38.     else
  39.  
  40. (* Wynik / stan koncowy *)
  41.     let dream_state = Array.map (fun (_, y) -> y) good_input_array in
  42.  
  43. (* Hashtable, ktory przechowuje stany *)
  44.     let mapa_stanow = Hashtbl.create 420420 in
  45.  
  46. (* Kolejka trzymajaca stany do rozpatrzenia *)
  47.     let do_rozpatrzenia = Queue.create () in
  48.     Queue.add ((Array.make dlugosc 0), 0) do_rozpatrzenia;
  49.  
  50. (* Funkcja nalania wody ze szklanki *)
  51.     let nalej (tablica, kroki) numer_szklanki =
  52.         let kopia = Array.copy tablica in
  53.         Array.set kopia numer_szklanki (Array.get pojemnosci numer_szklanki);
  54.         (kopia, kroki + 1) in
  55.  
  56. (* Funkcja wylania wody ze szklanki *)
  57.     let wylej (tablica, kroki) numer_szklanki =
  58.         let kopia = Array.copy tablica in
  59.         Array.set kopia numer_szklanki 0;
  60.         (kopia, kroki + 1) in
  61.  
  62. (* Funkcja przelania z jednej szklanki do drugiej *)
  63.     let przelej (tablica, kroki) z_tej do_tej =
  64.         let kopia = Array.copy tablica in
  65.         let z_tej_ile_ma = (Array.get kopia z_tej) in
  66.         let do_tej_ile_ma = (Array.get kopia do_tej) in
  67.         let do_tej_ile_moze_miec = (Array.get pojemnosci do_tej) in
  68.         if do_tej_ile_moze_miec - do_tej_ile_ma >= z_tej_ile_ma then
  69.         begin
  70.             Array.set kopia z_tej 0;
  71.             Array.set kopia do_tej (do_tej_ile_ma + z_tej_ile_ma);
  72.             (kopia, kroki + 1)
  73.         end
  74.         else
  75.         begin
  76.             Array.set kopia z_tej (z_tej_ile_ma - (do_tej_ile_moze_miec - do_tej_ile_ma));
  77.             Array.set kopia do_tej do_tej_ile_moze_miec;
  78.             (kopia, kroki + 1)
  79.         end in
  80.  
  81. (* Funkcja hashujaca *)
  82.     let hash tablica =
  83.         Array.fold_left (fun sum x -> abs (sum * 10 + x)) 0 tablica in
  84.  
  85. (* Dream state hash *)
  86.     let dream_hash = hash dream_state in
  87.  
  88. (* Pelna *)
  89.     let pelna stan i_numer =
  90.         (Array.get pojemnosci i_numer) = (Array.get (fst stan) i_numer) in
  91.  
  92. (* Pusta *)
  93.     let pusta stan i_numer =
  94.         0 = (Array.get (fst stan) i_numer) in
  95.  
  96. (* Obslugiwanie nowego stanu *)
  97.     let obsluz zmieniony_stan =
  98.         let changed_hash = hash (fst zmieniony_stan) in
  99.         if changed_hash = dream_hash && (fst zmieniony_stan) = dream_state then
  100.         begin
  101.             raise (Koniec (snd zmieniony_stan));
  102.         end
  103.         else if not (Hashtbl.mem mapa_stanow changed_hash) then
  104.         begin
  105.             Hashtbl.add mapa_stanow changed_hash [zmieniony_stan];
  106.             Queue.add zmieniony_stan do_rozpatrzenia;
  107.         end
  108.         else
  109.         let wyjeta_lista = Hashtbl.find mapa_stanow changed_hash in
  110.         let rec nie_ma zmieniony_stan lista =
  111.             match lista with
  112.             | hd :: tl -> if (fst hd) = (fst zmieniony_stan) then false else nie_ma zmieniony_stan tl
  113.             | [] -> true in
  114.         if nie_ma zmieniony_stan wyjeta_lista then
  115.         begin
  116.             Hashtbl.replace mapa_stanow changed_hash (zmieniony_stan :: wyjeta_lista);
  117.             Queue.add zmieniony_stan do_rozpatrzenia;
  118.         end
  119.         else () in
  120.  
  121. (* Looper *)
  122.     try
  123.         while not (Queue.is_empty do_rozpatrzenia) do
  124.             let aktualny_stan = Queue.take do_rozpatrzenia in
  125.             (* nalewanie *)
  126.             for i = 0 to dlugosc - 1 do
  127.                 if not (pelna aktualny_stan i) then
  128.                 let changed = nalej aktualny_stan i in
  129.                 obsluz changed
  130.             done;
  131.             (* wylewanie *)
  132.             for i = 0 to dlugosc - 1 do
  133.                 if not (pusta aktualny_stan i) then
  134.                 let changed = wylej aktualny_stan i in
  135.                 obsluz changed
  136.             done;
  137.             (* przelewanie *)
  138.             for i = 0 to dlugosc - 1 do
  139.                 if not (pusta aktualny_stan i) then
  140.                 begin
  141.                 for j = 0 to dlugosc - 1 do
  142.                     if j <> i && not (pelna aktualny_stan j) then
  143.                     begin
  144.                     let changed = przelej aktualny_stan i j in
  145.                     obsluz changed
  146.                     end
  147.                 done
  148.                 end
  149.             done
  150.         done;
  151.     -1
  152.     with Koniec wynik -> wynik ;;
  153.  
  154. (* Testy:
  155. assert(przelewanka [|(1, 0); (3, 0); (1, 0) |] = 0);;
  156. assert(przelewanka [|(1, 5); (3, 3); (1, 1) |] = 3);;
  157. assert(przelewanka [|(1, 0); (3, 0); (1, 0) |] = 0);;
  158. assert(przelewanka [|(3, 5); (3, 3); (1, 1) |] = 3);;
  159. assert(przelewanka [|(3, 3); (3, 3); (1, 0) |] = 3);;
  160. assert(przelewanka [|(3, 2); (3, 2); (1, 0) |] = 4);;
  161. assert(przelewanka [|(3, 1); (3, 1); (7, 1) |] = -1);;
  162. assert(przelewanka [|(3, 1); (3, 1); (7, 0) |] = 7);;
  163. assert(przelewanka [|(2,1); (1, 1); (7, 7) |] = 7);;
  164. assert(przelewanka [|(2,0); (1, 1); (7, 1) |] = 6);;
  165. assert(przelewanka [|(5,1); (1, 0); (7, 1) |] = 7);;
  166. assert(przelewanka [|(5,5); (1, 1); (7, 1) |] = 5);;
  167. assert(przelewanka [|(5,1); (1, 0); (7, 1) |] = 7);;
  168. assert(przelewanka [|(5,3); (3, 3); (7, 1) |] = 4);;
  169. assert(przelewanka [|(5,3); (3, 0); (7, 4) |] = 3);;
  170. assert(przelewanka [|(5,0); (3, 3); (7, 4) |] = 2);;
  171. assert(przelewanka [|(5,0); (3, 0); (7, 7) |] = 1);; *)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement