haskell 基础题解(57)

整数的划分

【题目】把一个正整数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 模式。以后再说吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值