整数的划分
【题目】把一个正整数N,可以划分为多个数的和的形式。如果规定划分出来的最小数是1,最大数是它本身,则对给定的N,你能列出它的所有划分形式吗?
比如:N=4,可以划分为:
1+1+1+1, 1+1+2, 1+3, 2+2, 4
这类问题是haskell 的强项。
问题天然就是一种递归的形式。对于N,如果划出1,则剩下的N-1如何划分?
如果划出2, 剩下的要求最小划分数字为2, 怎么划分?(为什么要限定最小?要不然与前边先划出1的那个重复了。可以规定:后划出来的数字不小于前边划出的数字,这样就避开重复了)
这类问题一般都是想的时候要想好久,但写出来十分短。
hua :: Int -> [[Int]]
hua n = f n 1
where ------- f 也是求 n 的划分,但要求最小数是 m
f n m | m > n = []
| m == n = [[n]]
| otherwise = map (m:) (f (n-m) m) ++ f n (m+1)
main :: IO ()
main = putStr $ unlines $ map show (hua 4)
这个递归还好,许多递归表示法虽然简短,但中间有许多重复的计算。
如果遇到这种情况,可以改为动态规划
实质就是,仔细安排计算的顺序,使得在后面的计算中用到的数据刚好前边已经计算好了。
在 haskell 中因为不允许使用可变的量,因而没办法用一个数组来缓存。可以共用一个Map来做,但它也是不可改的,必须在函数间传递它。如果要消除这个不爽,可以用State Monad 模式。以后再说吧。