(* 我們可以定義在第 n 處斷行=>除了斷行點以外的文字消失,的成本函數 cost(n),成本函數越小越好。 這時後需要用動態規劃解決。 badness (k, n)是指k~n-1處若塞於一行,且n處斷行時的懲罰函數(等下介紹),越小越好 cost(n) = baness(0,n) 若其為有限,否則 min of k in 0...n-1 of badness(k, n) + cost(k) 懲罰函數badness定義是:若lineWidth >= widthBetween(a,b),則為二者之差的三次方,否則是無限大。 k >= n badness(k, n) = (lineWidth - widthBetween(k, n) )^3 if lineWidth >= widthBetween(k+1, n) infinity elsewhere widthBetween(a,b)係指 a到b 塞在一行時的寬度 widthBetween(a,b) = hw[b] + (sum{i=a...b-1} of ow[i] *) openPrintf
let lineWidth = 12.0;; (*一行最大寬度*)
let widthBetween a b = if a> b then raise (Failure"Exception: widthBetween a b, a <=b ") else (List.nth segWithLengthList b).hw +. (sumOfOw a (b-1) segWithLengthList);; let badness k n = let remainedSpaceWidth = lineWidth -. (widthBetween k n) in if remainedSpaceWidth >= 0.then remainedSpaceWidth ** 3. else infinity;;
let minIndex = ref0;; (*cost(x)發生的最小的k)值*)
(*動態規劃存放 (min cost, 其中的 k 滿足 min cost) 之處*) (*格式: n (minValue, minIndex) *) let costKStorage = Hashtbl.create 10;;
letrec cost n = ifHashtbl.mem costKStorage n then(*若是已經存儲了,即用裡面的值,避免重複運算*) let (minValue, minIndex) = Hashtbl.find costKStorage n in minValue elseif (badness 0 n) < infinity then (badness 0 n) else let compareList = List.init n (fun k -> (badness k n) +. cost k) in (*找最小值*) let findMin lst = List.fold_left min infinity lst in let minValue = findMin compareList in(*最小值*) (*找最小值所在的索引index值*) let findMinIndex lst = List.fold_left (fun pos i -> if (List.nth lst i) == minValue then i else pos) (-1) (List.init (List.length lst) (fun x -> x)) in let minIndex = findMinIndex compareList in let _ = Hashtbl.add costKStorage n (minValue, minIndex) in minValue;;
val lineWidth : float = 12.
val widthBetween : int -> int -> float = <fun>
val badness : int -> int -> float = <fun>
val minIndex : int ref = {contents = 0}
val costKStorage : ('_weak11, '_weak12) Hashtbl.t = <abstr>
val cost : int -> float = <fun>
1 2 3 4 5 6 7 8
(*sumOfOw : 上文的(sum{i=a...b} of ow[i]*) (* sumOfOwAux:輔助函數*) letrec sumOfOwAux i start final sum list = if i < start then sumOfOwAux (i+1) start final sum list elseif (i>= start && i <= final) then sumOfOwAux (i+1) start final (sum +. (List.nth list i).ow) list else sum ;;
let sumOfOw start final list = sumOfOwAux 0 start final 0.0list;;
val sumOfOwAux :
int -> int -> int -> float -> segment_with_length list -> float = <fun>
val sumOfOw : int -> int -> segment_with_length list -> float = <fun>
1 2 3 4 5 6 7 8
(*算到第11之處的成本*) (*結果 no thing can stop crocodile ...........^ 最多只能塞到箭頭處*) cost 11;;
- : float = 179.
1 2 3
(*找 costKStorage 目前的值*) let a = ref""in let _ = (Hashtbl.iter (fun x y -> let (y1,y2) = y in a := !a ^ (sprintf "%d : %f %d\n" x y1 y2)) costKStorage) in !a;;
letrec findBreakPointAux res k = ifHashtbl.mem costKStorage k then let (minValue, minIndex) = Hashtbl.find costKStorage k in findBreakPointAux (List.append res [k]) minIndex else (List.append res [k]);; let findBreakPoint n = findBreakPointAux [] n;;
val findBreakPointAux : int list -> int -> int list = <fun>
val findBreakPoint : int -> int list = <fun>