指定された配列内のすべてのパーセンテージが 100 未満であると仮定すると (いずれにせよ、100 以上の要素があった場合は、すぐに数えて削除することができます)、100% の各バレルは 2 つ未満の配列要素から作成することはできません。 100% バレルの数は、配列の合計を 100 で割った値を超えることはできません。したがって、調べる可能性は次のように制限されます。
maxNumBarrels array = min (div (sum array) 100) (div (length array) 2)
次の Haskell コードは関数 を提供します。この関数はdivide
、配列を繰り返しなしで n 個のパーティションのすべてのバリエーションに分割します (つまり、パーティション内のパーティション順序と要素順序の両方が無視されます)。関数maxBarrels
は逆方向に検索し、最初に配列を maxNumBarrels パーティションに分割し (合計が >=100 である maxNumBarrels 要素を含む結果を検索します)、答えが見つかるか null セットが返されるまで、パーティションの数を徐々に減らします。
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)...