open Format let n = int_of_string Sys.argv.(1) let target_out = Array.create n 0 let target_plink = Array.create n 0 let () = try while true do let s = read_line () in Scanf.sscanf s "%d -> (%d,%d)" (fun i j k -> target_out.(i) <- j; target_plink.(i) <- k) done with End_of_file -> () let () = for i = 0 to n-1 do printf "%d -> (%d,%d)@." i target_out.(i) target_plink.(i) done; printf "---@." (* the infamous bubble sort *) let t = Array.copy target_out let cur = Array.init n (fun i -> i) let plink = Array.create n 0 let solution = ref [] let matrix = Array.create_matrix n n [] let swap line i = let tmp = t.(i) in t.(i) <- t.(i+1); t.(i+1) <- tmp; plink.(cur.(i)) <- plink.(cur.(i)) + 1; let tmp = cur.(i) in cur.(i) <- cur.(i+1); cur.(i+1) <- tmp; match !solution with | (l, sw) :: r when l = line -> solution := (l, i :: sw) :: r | sol -> solution := (line, [i]) :: sol let update_matrix line = for i = 0 to n-2 do matrix.(cur.(i)).(cur.(i+1)) <- (line, i) :: matrix.(cur.(i)).(cur.(i+1)); matrix.(cur.(i+1)).(cur.(i)) <- (line, i) :: matrix.(cur.(i+1)).(cur.(i)) done let () = let line = ref 0 in (* hack for n=50 *) if n = 50 then begin for i = 48 downto 44 do update_matrix !line; swap !line i; incr line done end; try while true do update_matrix !line; let modif = ref false in let i = ref 0 in while !i < n-1 do if t.(!i) > t.(!i+1) then begin swap !line !i; modif := true; i := !i + 2 end else incr i done; if not !modif then raise Exit; incr line done with Exit -> update_matrix !line let diff = Array.init n (fun i -> target_plink.(i) - plink.(i)) let sdiff = ref 0 let () = printf "diff: "; Array.iteri (fun i di -> printf "%d " di) diff; printf "@." let () = for i = 0 to n-1 do assert (target_out.(cur.(i)) = i); assert (diff.(i) >= 0); sdiff := !sdiff + diff.(i) done; assert (!sdiff mod 2 = 0) (* (* affichage matrice *) let () = for i = 0 to n-1 do for j = 0 to n-1 do match matrix.(i).(j) with | [] -> printf " ." | (l,_) :: _ -> printf "%2d" l done; printf "@." done *) open Search module I = struct (* the state is imperative *) let success () = try Array.iteri (fun _ di -> assert (di >= 0); if di > 0 then raise Exit) diff; true with Exit -> false (* moves *) type move = int * int * int let deg = Array.create n 0 (* maximal constraint-based selection *) let moves () = let degree i = let c = ref 0 in for j = 0 to n-1 do if matrix.(i).(j) <> [] && diff.(j) > 0 then incr c done; !c in for i = 0 to n-1 do deg.(i) <- degree i done; let min_d = ref 0 in let min_val = ref max_int in for i = 1 to n-1 do if diff.(i) > 0 && deg.(i) < !min_val then begin min_d := i; min_val := deg.(i) end done; let ml = ref [] in for i = 0 to n-1 do if diff.(i) > 0 && matrix.(!min_d).(i) <> [] then ml := (i, !min_d, min diff.(i) diff.(!min_d)) :: !ml done; let ml = List.sort (fun (i1,_,_) (i2,_,_) -> deg.(i1) - deg.(i2)) !ml in let todo = ref 0 in for i = 0 to n-1 do if diff.(i) > 0 then incr todo done; match List.rev ml with (* heuristics go here *) (* | ((i1,_,_) as m1) :: ((i2,_,_) as m2) :: _ when !todo > 50 -> if diff.(!min_d) > diff.(i1) then [m1] else [m1; m2] *) | m1 :: _ :: _ -> [m1; List.hd ml] | _ -> ml let ok () = try for i = 0 to n-1 do if diff.(i) > 0 then begin let s = ref 0 in for j = 0 to n-1 do if matrix.(i).(j) <> [] then s := !s + diff.(j) done; if !s < diff.(i) then raise Exit end done; true with Exit -> false let moves () = if ok () then moves () else [] let do_move (i,j,k) = diff.(i) <- diff.(i) - k; diff.(j) <- diff.(j) - k let undo_move (i,j,k) = diff.(i) <- diff.(i) + k; diff.(j) <- diff.(j) + k (* visited states are put in a hash table using function [mark] *) type marked_state = unit let mark () = None end module B = ImperativeDFS(I) let display_one_swap idx = for i = 0 to idx-1 do Format.printf "|" done; Format.printf "><"; for i = idx+2 to n-1 do Format.printf "|" done; Format.printf "@." let display_swaps sl = let rec display i = function | j :: sl when j = i -> printf "><"; display (i+2) sl | sl -> if i < n then begin printf "|"; display (i+1) sl end in display 0 sl; printf "@." let compact tps il = let l,il = List.partition (fun ((l,_),_) -> l <= tps) il in let rec build sl = function | [] -> sl | ((t,i),k) :: l -> let s,l = List.fold_right (fun (((t',i'),k') as tik') (s,l) -> if List.for_all (fun j -> i' < j-1 || i' > j+1) s then (i' :: s, if k' = 1 then l else ((t',i'),k'-1)::l) else (s, tik' :: l) ) l ([i],[]) in let s = List.sort compare s in build (s :: sl) (if k = 1 then l else ((t,i),k-1)::l) in build [] l, il let () = let l = B.search () in List.iter (fun (i,j,k) -> printf "(%d,%d,%d)" i j k) l; printf "@."; printf "YES!@."; let l = List.map (fun (i,j,k) -> (List.hd matrix.(i).(j), k)) l in let il = List.sort (fun ((l1,i1),k1) ((l2,i2),k2) -> l1 - l2) l in List.iter (fun ((t,i),k) -> printf "((%d,%d),%d)" t i k) il; printf "@."; let rec display_inter tps = function | [] -> [] | (((l,i),k) :: _) as il when l <= tps -> let sl,il = compact tps il in List.iter (fun s -> display_swaps s; display_swaps s) sl; display_inter tps il | il -> il in let rec display il = function | [] -> let il = display_inter max_int il in assert (il = []) | (tps, swaps) :: sol -> let il' = display_inter tps il in display_swaps (List.rev swaps); display il' sol in display il (List.rev !solution)