再帰スキームに関するこのブログから、組織型を理解しようとしています。ブログに記載されているように、変更を行う問題を解決するために例を実行しているときに問題に直面しています。
両替問題は、通貨の額面を取り、特定の金額を作成するために必要なコインの最小数を見つけようとします。以下のコードはブログから取得したもので、答えを計算する必要があります。
{-# LANGUAGE DeriveFunctor #-}
module Main where
import Control.Arrow ( (>>>) )
import Data.List ( partition )
import Prelude hiding (lookup)
newtype Term f = In {out :: f (Term f)}
data Attr f a = Attr
{ attribute :: a
, hole :: f (Attr f a)
}
type CVAlgebra f a = f (Attr f a) -> a
histo :: Functor f => CVAlgebra f a -> Term f -> a
histo h = out >>> fmap worker >>> h
where
worker t = Attr (histo h t) (fmap worker (out t))
type Cent = Int
coins :: [Cent]
coins = [50, 25, 10, 5, 1]
data Nat a
= Zero
| Next a
deriving (Functor)
-- Convert from a natural number to its foldable equivalent, and vice versa.
expand :: Int -> Term Nat
expand 0 = In Zero
expand n = In (Next (expand (n - 1)))
compress :: Nat (Attr Nat a) -> Int
compress Zero = 0
compress (Next (Attr _ x)) = 1 + compress x
change :: Cent -> Int
change amt = histo go (expand amt)
where
go :: Nat (Attr Nat Int) -> Int
go Zero = 1
go curr@(Next attr) =
let given = compress curr
validCoins = filter (<= given) coins
remaining = map (given -) validCoins
(zeroes, toProcess) = partition (== 0) remaining
results = sum (map (lookup attr) toProcess)
in length zeroes + results
lookup :: Attr Nat a -> Int -> a
lookup cache 0 = attribute cache
lookup cache n = lookup inner (n - 1) where (Next inner) = hole cache
これで評価change 10
すると 3 になります。
これは... 10 の値のコイン 1 枚を使用して 10 を作ることができるため、間違っています。
だから私はそれが、与えられた金額を稼ぐことができる方法の最大数を見つけるコインチェンジ問題を解決しているのかもしれないと考えました. たとえば、 、 、 、 の 4 つの方法で 10 を{ 1, 1, ... 10 times }
作成{ 1, 1, 1, 1, 5}
でき{ 5, 5 }
ます{ 10 }
。
では、このコードの何が問題になっているのでしょうか? 問題を解決する上でどこが間違っていますか?
TLDR
再帰スキームに関するこのブログの上記のコードは、金額を変更する最小または最大の方法を見つけていません。なぜ機能しないのですか?