基于Haskell实现输入组合寻优:求解计算式最小输出值
解决Haskell寻优问题:找到longCalc的最小输入组合
嘿,我来帮你搞定这个寻找最小计算结果的问题!首先咱们先理清楚你已经写的代码,然后一步步完善寻优逻辑——顺便说一句,直接生成allPairs这种超大列表可不太现实,后面我会给你更高效的方案。
先回顾你的基础代码
你已经定义了计算函数和所有可能输入的配对列表:
longCalc a b c d e f g = a*b + c - d/e*f + g allPairs = [(show [a,b,c,d,e,f,g], longCalc a b c d e f g) | a<-[1..40],b<-[1..40],c<-[1..40],d<-[1..40],e<-[1..40],f<-[1..40],g<-[1..40]]
方案1:基于现有列表的寻优(注意:仅理论可行)
如果非要用allPairs来找最小值,Haskell的Data.List模块里的minimumBy函数正好能派上用场。我们只需要比较每个元组的第二个元素(也就是计算结果):
首先导入必要的模块:
import Data.List (minimumBy) import Data.Ord (comparing)
然后定义寻优函数:
findMinInput :: (String, Double) findMinInput = minimumBy (comparing snd) allPairs
为什么说理论可行?
40^7等于163840000000个元素——这可是百亿级别的列表,你的内存根本装不下,运行起来直接就会崩溃。所以这个方法只能用来理解思路,实际用不了。
方案2:高效遍历跟踪最小值(推荐实际使用)
我们可以不用生成整个列表,而是逐个遍历所有输入组合,只保留当前找到的最小值,这样内存占用几乎是常数:
findMinEfficient :: (String, Double) findMinEfficient = go 1 1 1 1 1 1 1 ("", 1/0) -- 初始最小值设为无穷大 where -- 递归遍历所有输入组合 go a b c d e f g currentMin | a > 40 = currentMin -- 所有a遍历完,返回结果 | b > 40 = go (a+1) 1 1 1 1 1 1 currentMin -- 当前b遍历完,a+1 | c > 40 = go a (b+1) 1 1 1 1 1 currentMin | d > 40 = go a b (c+1) 1 1 1 1 currentMin | e > 40 = go a b c (d+1) 1 1 1 currentMin | f > 40 = go a b c d (e+1) 1 1 currentMin | g > 40 = go a b c d e (f+1) 1 currentMin | otherwise = let currentVal = longCalc a b c d e f g -- 比较当前值和已存最小值,更新最小值 newMin = if currentVal < snd currentMin then (show [a,b,c,d,e,f,g], currentVal) else currentMin in go a b c d e f (g+1) newMin
这个版本会逐个计算每个输入组合的结果,只记住最小的那个,不会占用大量内存,运行起来流畅很多。
方案3:数学分析直接找最优解(最高效)
其实咱们可以先分析longCalc的表达式,直接推导出最小值对应的输入:
把表达式整理一下:
longCalc = a*b + c - (d*f)/e + g
要让整个结果最小,我们需要:
a*b尽可能小:a和b都取最小值1,得到1*1=1c尽可能小:取最小值1(d*f)/e尽可能大:d和f取最大值40,e取最小值1,得到(40*40)/1=1600g尽可能小:取最小值1
代入计算:1 + 1 - 1600 + 1 = -1597,对应的输入组合是[1,1,1,40,1,40,1]。
这种方法完全不需要遍历,直接就能得到结果,效率最高!
内容的提问来源于stack exchange,提问作者uglyoldbob




