n個のサイコロが与えられ、それぞれにm個の面があります。n 個のサイコロをすべて転がし、各サイコロを振って得たすべての出目の合計を書き留めます。合計が x 以上の場合は勝ち、それ以外の場合は負けです。勝つ確率を求めてください。
1 から m (サイズ n ) のすべての組み合わせを生成し、合計が x を超える組み合わせのみをカウントすることを考えました。ウェイの総数は m^n
その後は、両方を分割するだけです。
より良い方法はありますか?
n個のサイコロが与えられ、それぞれにm個の面があります。n 個のサイコロをすべて転がし、各サイコロを振って得たすべての出目の合計を書き留めます。合計が x 以上の場合は勝ち、それ以外の場合は負けです。勝つ確率を求めてください。
1 から m (サイズ n ) のすべての組み合わせを生成し、合計が x を超える組み合わせのみをカウントすることを考えました。ウェイの総数は m^n
その後は、両方を分割するだけです。
より良い方法はありますか?
[編集: jpalacek が指摘したように、時間の計算量が間違っていました -- これを修正しました。]
最初に質問に変更することにより、動的計画法でこれをより効率的に解決できます。
n 個のサイコロから少なくとも x を得る方法は何通りありますか?
これを f(x, n) と表現します。そしたらそうなるに違いない
f(x, n) = sum(f(x - i, n - 1)) すべての 1 <= i <= m.
つまり、最初のサイコロの目が 1 の場合、残りの n - 1 個のサイコロの合計は少なくとも x - 1 になる必要があります。最初のサイコロが 2 の場合、残りの n - 1 サイコロの合計は少なくとも x - 2 になる必要があります。等々。
合計には m 個の項があるため、この関数をメモすると、O(m^2*n^2) になります。これは、この合計作業を最大で (m * n) * n 回実行する必要があるためです (つまり、最初のパラメーター x <= m * n であると仮定して、関数への入力の一意のセットごとに 1 回)。
確率を求める最後のステップとして、f(x, n) の結果を可能な結果の総数、つまり m^n で割ります。
@j_random_hackerの基本的に正しい答えを追加するために、次のことに注意すると、さらに速くすることができます
f(x, n) = f(x-1, n) - f(xm-1, n-1) + f(x-1, n-1) if x>m+1
O(1)
この方法では、各値の計算に時間を費やすだけf
です。
//curFace 値を渡すと組み合わせの重複は許可されません
//3 つのサイコロの場合 - 合計 8 - 2 4 2 と 2 2 4 は同じ組み合わせなので、1 つとしてカウントする必要があります
int sums(int totSum,int noDices,int mFaces,int curFace,HashMap<String,Integer> map)
{
int count=0;
if (noDices<=0 || totSum<=0)
return 0;
if (noDices==1)
{
if (totSum>=1 & totSum<=mFaces)
return 1;
else
return 0;
}
if (map.containsKey(noDices+"-"+totSum))
return map.get(noDices+"-"+totSum);
for (int i=curFace;i<=mFaces;i++)
{
count+=sums(totSum-i,noDices-1,mFaces,i,map);
}
map.put(noDices+"-" +totSum,count);
return count;
}