solve_2.ml 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. open Stdio
  2. let input =
  3. let line = In_channel.input_line In_channel.stdin in
  4. match line with
  5. | None -> ""
  6. | Some x -> x
  7. ;;
  8. type file_block = {
  9. id: int;
  10. size: int;
  11. empty_space : int;
  12. can_move: bool;
  13. }
  14. let rec print_disk_map = function
  15. | [] -> ()
  16. | x::tl -> (printf "(%d %d %d %b) - " x.id x.size x.empty_space x.can_move; print_disk_map tl)
  17. let expand dm =
  18. let rec aux i acc=
  19. if (i >= String.length dm) then
  20. acc
  21. else (if (i == String.length dm -1)
  22. then
  23. let file_id = (i/2) in
  24. let file_size = (int_of_char dm.[i] - int_of_char '0') in
  25. let new_block = {id = file_id; size = file_size; empty_space=0; can_move = (file_id != 0)} in
  26. new_block :: acc
  27. else
  28. let file_id = (i/2) in
  29. let file_size = (int_of_char dm.[i] - int_of_char '0') in
  30. let empty_spc = (int_of_char dm.[i+1] - int_of_char '0') in
  31. let new_block = {id = file_id; size = file_size; empty_space=empty_spc; can_move = (file_id != 0)} in
  32. aux (i+2) (new_block :: acc))
  33. in
  34. aux 0 []
  35. ;;
  36. let reverse_list = List.rev;;
  37. let fill_empty_space file1 file2 gain_space =
  38. let new_ept_space = if (gain_space) then file1.empty_space - file2.size + file2.empty_space + file2.size
  39. else file1.empty_space - file2.size
  40. in
  41. let n_file1 = {id = file1.id; size = file1.size; empty_space = 0; can_move=file1.can_move} in
  42. let n_file2 = {id = file2.id; size = file2.size; empty_space = new_ept_space; can_move = false} in
  43. n_file1::[n_file2]
  44. ;;
  45. let custom_findindex f l =
  46. let index = List.find_index f l in
  47. match index with
  48. | None -> -1
  49. | Some i -> i
  50. ;;
  51. let cant_move f =
  52. {id=f.id; size=f.size; empty_space=f.empty_space; can_move=false};;
  53. let add_empty_space i1 i2 lst=
  54. if (i1 == i2) then []
  55. else
  56. let imp_f = List.nth lst i1 in
  57. let mov_f = List.nth lst i2 in
  58. [{id=imp_f.id;
  59. size=imp_f.size;
  60. empty_space=imp_f.empty_space+mov_f.size+mov_f.empty_space;
  61. can_move=imp_f.can_move}];;
  62. let sublist n j lst =
  63. List.take (j - n) (List.drop n lst)
  64. ;;
  65. let compact reversed_dm =
  66. let ordered_dm = (reverse_list reversed_dm) in
  67. let size_dm = List.length ordered_dm in
  68. let rec aux dm =
  69. (* printf "\n -------------- \n"; *)
  70. (* print_disk_map dm; *)
  71. if (List.for_all (fun f -> f.can_move == false) dm) then dm
  72. else
  73. let reverse_dm = (reverse_list dm) in
  74. let cur_file_to_move_index = (size_dm - (custom_findindex (fun f -> f.can_move == true) reverse_dm) - 1) in
  75. let cur_file_to_move = (List.nth dm cur_file_to_move_index) in
  76. let new_index = (custom_findindex (fun f -> f.empty_space >= cur_file_to_move.size) dm) in
  77. let new_dm =
  78. (if (new_index == -1 || new_index >= cur_file_to_move_index) then
  79. (List.take cur_file_to_move_index dm)@[(cant_move cur_file_to_move)]@(List.drop (cur_file_to_move_index + 1) dm)
  80. else
  81. let impacted_file = List.nth dm new_index in
  82. let is_impacted_file_space =
  83. if (cur_file_to_move_index - new_index == 1) then cur_file_to_move_index else (cur_file_to_move_index - 1) in
  84. (List.take new_index dm)@
  85. (fill_empty_space impacted_file cur_file_to_move (cur_file_to_move_index == new_index + 1))@
  86. (sublist (new_index+1) (is_impacted_file_space) dm)@
  87. (add_empty_space is_impacted_file_space cur_file_to_move_index dm)@
  88. (List.drop (cur_file_to_move_index+1) dm)
  89. )
  90. in
  91. aux new_dm
  92. in
  93. aux ordered_dm
  94. ;;
  95. let calculate_file_block_cs file_block id=
  96. let rec aux acc counter=
  97. if (counter == file_block.size) then acc
  98. else aux (file_block.id*(id+counter) + acc) (counter+1)
  99. in
  100. aux 0 0
  101. ;;
  102. let calculate_checksum dm=
  103. let rec aux id accum =
  104. function
  105. | [] -> accum
  106. | x::tl -> aux (id+x.size+x.empty_space) ((calculate_file_block_cs x id)+accum) tl
  107. in
  108. aux 0 0 dm;;
  109. let solve =
  110. let dm = expand input in
  111. calculate_checksum (compact dm);
  112. ;;
  113. let () =
  114. printf "Total: %d\n" solve;;