このソリューションは機能するはずです-システムでどれくらいの時間がかかるかわかりません。
from itertools import product
lg = (p for p in product(xrange(1,13,1),repeat=10) if sum(p) == 70)
results = {}
for l in lg:
results[l] = [p for p in product(xrange(1,min(l),1),repeat=10)]
最初に「トップ10」を作成します。次に、各「トップ10」に、可能な「次の10」アイテムのリストを追加します。このリストでは、最大値が「トップ10」の最小アイテムに制限されています。
結果は、key
が「トップ10」であり、値が可能な「次の10」のリストである辞書です。
解決策(要件に適合する組み合わせの量)は、次のようにすべての結果dictのリストの数を数えることです。
count = 0
for k, v in results.items():
count += len(v)
そしてcount
結果になります。
アップデート
さて、私はこれを行うための少し良い方法を考えました。
from itertools import product
import math
def calc_ways(dice, sides, top, total):
top_dice = (p for p in product(xrange(1,sides+1,1),repeat=top) if sum(p) == total)
n_count = dict((n, math.pow(n, dice-top)) for n in xrange(1,sides+1,1))
count = 0
for l in top_dice:
count += n_count[min(l)]
return count
「次の10」の長さだけを数えるので、「トップ10」の「最小」の数値ごとにオプションの量を事前に計算するだけだと思ったので、それを行う辞書を作成しました。上記のコードは、小さな辞書、カウンター、およびジェネレーターのみで構成されているため、はるかにスムーズに実行されます。ご想像のとおり、まだまだ時間がかかると思いますが、最初の100万件を1分以内で実行しました。だから私はそれが実行可能な範囲内にあると確信しています。
幸運を :)
アップデート2
あなたからの別のコメントの後、私は自分が間違っていることを理解し、それを修正しようとしました。
from itertools import product, combinations_with_replacement, permutations
import math
def calc_ways(dice, sides, top, total):
top_dice = (p for p in product(xrange(1,sides+1,1),repeat=top) if sum(p) == total)
n_dice = dice-top
n_sets = len(set([p for p in permutations(range(n_dice)+['x']*top)]))
n_count = dict((n, n_sets*len([p for p in combinations_with_replacement(range(1,n+1,1),n_dice)])) for n in xrange(1,sides+1,1))
count = 0
for l in top_dice:
count += n_count[min(l)]
return count
ご想像のとおり、これはかなりの惨事であり、正しい答えを与えることすらできません。これは数学者に任せるつもりだと思います。これを解決する私の方法は単純に次のようになるからです。
def calc_ways1(dice, sides, top, total):
return len([p for p in product(xrange(1,sides+1,1),repeat=dice) if sum(sorted(p)[-top:]) == total])
これはエレガントな1行のソリューションであり、正しい答えを提供しますcalc_ways1(5,6,3,15)
が、問題には永遠にかかりますcalc_ways1(20,12,10,70)
。
とにかく、私の愚かな考えではなく、数学は確かにこれを進める方法のようです。