函数式编程解百鸡问题
2022-06-07 本文已影响0人
redexpress
问题
百鸡问题来自《张邱建算经》,原文:今有鸡翁一直钱五,鸡母一直前三,鸡雏三直钱一,凡百钱买百鸡。问:鸡翁、母、雏各几何?
这个问题有三个未知数,但却只能列两个方程。属于不确定方程问题。如果直接推算比较复杂,可以参考“百鸡问题”史话,而用编程实现比较直接。
命令式编程
用命令式编程有两种解法,下面是Python程序
方法一:多重循环
for x in range(0, 21):
for y in range(0, 34):
z = 100 - x - y
if x * 5 + y * 3 + z / 3 == 100:
print(x, y, z)
方法二:列表演算
思路同方法一,Python 等编程语言支持列表演算,可以用一行代码写完
[print(x, y, 100 - x - y) for x in range(21) for y in range(34) if x*5+y*3+(100-x-y)/3 == 100]
方法三:单循环加逻辑推理
只循环公鸡,剩下的钱买小鸡,鸡的总量超过100的,每超过8只就把9只小鸡换成1只母鸡,这样总量就是100。
for x in range(21):
z = (20 - x) * 15
y = (x + z - 100) // 8
if (x + z - 100) % 8 == 0 and (x + z >= 100):
print(x, y, 100-x-y)
函数式编程
函数式编程语言没有for/while循环语句,可以通过递归实现,下面是Scheme代码:
(define (chicken)
(chicken-iter 0 0))
(define (chicken-iter a b)
(cond [(eq? 100 (+ (* a 5) (* b 3) (/ (- 100 a b) 3)))
(printf "~s ~s ~s\n" a b (- 100 a b))])
(cond [(and (eq? a (truncate 100/5)) (eq? b (truncate 100/3)))
(display "")]
[else (if (eq? b (truncate 100/3))
(chicken-iter (+ a 1) 0)
(chicken-iter a (+ b 1)))]))
(chicken)
而Haskell支持列表演算,代码可以很简短:
[(x, y, 100-x-y) | x <- [0..20], y<-[0..33], x*5+y*3+(100-x-y) `div` 3 == 100, (100-x-y) `mod` 3==0]
即使你不了解Haskell,代码也不难理解。第三种方法的函数式编程感兴趣读者可以自行完成。