假设给定数组中的所有百分比都小于 100(在任何情况下,如果有元素等于或大于 100,我们可以立即计数并删除它们),每桶 100% 不能由少于两个数组元素创建,并且100% 桶的数量不能超过数组的总和除以 100。因此,检查的可能性受以下限制:
maxNumBarrels array = min (div (sum array) 100) (div (length array) 2)
下面的 Haskell 代码提供了函数 ,divide
它将数组划分为 n 个分区的所有变体而不重复(即,分区中的分区顺序和元素顺序都被忽略)。函数 ,maxBarrels
向后搜索,首先将数组划分为 maxNumBarrels 分区(搜索总和 >=100 的 maxNumBarrels 元素的结果),然后逐渐减少分区数量,直到找到答案或返回空集。
import Data.Map (adjust, fromList, toList)
divide xs n = divide' xs (zip [0..] (replicate n [])) where
divide' [] result = [result]
divide' (x:xs) result = do
index <- indexes
divide' xs (toList $ adjust (x :) index (fromList result)) where
populated = map fst . filter (not . null . snd) $ result
indexes = populated ++ if any (null . snd) result
then [length populated]
else []
maxBarrels xs = allDivided maxNumBarrels where
maxNumBarrels = min (div (sum xs) 100) (div (length xs) 2)
allDivided count | count == 0 = []
| not (null divided) = divided
| otherwise = allDivided (count - 1)
where divided = filter ((==count) . length)
. map (filter ((>=100) . sum))
. map (map snd)
. divide xs $ count
输出:
*Main> maxBarrels [10,15,20,35,55,65]
[[[55,20,15,10],[65,35]],[[55,35,10],[65,20,15]]]
*Main> maxBarrels [99,99,99]
[[[99,99,99]]]
*Main> maxBarrels [99,99,99,10,15,25,35,55,65]
[[[15,10,99],[25,99],[35,99],[65,55]] ...(the first of 144 immediate results)...