私は(間違っていますが、我慢してください)コインの系列が最適であることを推測しました。コインは指数関数的に間隔が置かれるため、追加されたコインごとに可能な限り残りの値を減らします。あなたの例では、これはます。{bi| b=⌈n1/m⌉,0≤i<m}{1,3,9,27,81}
これは、ノッチより良い(ある)USDの宗派(より)、それは平均何もする必要はありません。390/99420/99
私は今、分析的にこれにアプローチする方法がわからないので、力ずくでいくつかの数を取得するためにハッキーなHaskellスクリプトを書きました。
指数分布が常に最良であるとは限りません。たとえば、、に対してが得られることがあります。が、用。私の遅いマシンは到達できないので、ここでは小さい数を使用する必要があります。(m,n)=(4,30)75/29{20,8,3,1}87/29{27,9,3,1}(5,100)
しかし、エラーはかなり小さいように見えました。ほとんどの場合、合計の除算は1.0 ...で始まる何かをもたらすので、さらにいくつかのテストを実行しました。
およびテストセットから、標準偏差の最良の解と比較して、指数関数的増加の平均誤差が得られます。3≤m≤56≤n≤401.120.085
テストパラメーターはかなり小さいと主張するかもしれませんが、指摘するように、設定すると、総当たりになるだけです(おそらくより優れた解決策がありますが、これは緩めていくつかのことを行う優れた言い訳でした) Haskell)。n=100
試してみたい場合は、ここが私のテストスイートです。
getopt :: [Integer] -> Integer -> [Integer]
getopt _ 0 = []
getopt coins target = choice:(getopt viable $ target - choice)
where
viable = filter ((>=) target) coins
choice = maximum $ viable
getsum :: [Integer] -> Integer -> Int
getsum coins n = sum $ map length $ map (getopt coins) [1..(n-1)]
buildall :: Integer -> Integer -> [[Integer]]
buildall 1 _ = [[1]]
buildall m n = foldl1 (++) $ map (\am -> map (\x -> x:am) [((head am)+1) .. (n-1)]) $ buildall (m-1) n
buildguess :: Integer -> Integer -> [Integer]
buildguess m n = reverse $ map ((^) $ ceiling $ (fromInteger n)**(1.0/(fromInteger m))) [0..(m-1)]
findopt :: Integer -> Integer -> ([Integer],Int)
findopt m n = foldl1 (\(l@(_,lhs)) -> (\(r@(_,rhs)) -> (if (lhs < rhs) then l else r)))
$ map (\arr -> (arr,getsum arr n)) $ buildall m n
intcast :: (Integral a,Num b) => a -> b
intcast = fromInteger.toInteger
esterror :: Integer -> Integer -> Double
esterror m n = (intcast $ getsum (buildguess m n) n) / (intcast best)
where (_,best) = findopt m n
私はテストを実行しました
map (uncurry esterror) [(m,n) | m <- [3..5], n <- [6..40] ]