Python
 Computer >> コンピューター >  >> プログラミング >> Python

Pythonでサイコロの出目の合計がターゲットと一致する組み合わせの数を求める

d個のサイコロがあり、それぞれのサイコロには1からfまでの数字が書かれた面があるとします。このとき、出た目の合計がターゲットの値と一致するような振り方(全 fd 通りのうち)の数を、10^9 + 7 で割った余りとして求めます。

例えば、d = 2、f = 6、target = 7 の場合、答えは6になります。6面のサイコロ2つを振って合計が7になる組み合わせは、「1+6」「2+5」「3+4」「4+3」「5+2」「6+1」の6通り存在するためです。

解法のアプローチ

この問題は動的計画法(DP)を使うことで効率的に解けます。手順は以下の通りです。

  • m := 10^9 + 7(剰余を取るための定数)を定義する
  • d × (t + 1) のサイズのdpテーブルを作成し、すべて0で初期化する
  • i を 0 から d − 1 まで繰り返す
    • j を 0 から t まで繰り返す
      • i = 0 の場合:j が 1 以上 f 以下なら dp[i, j] := 1、それ以外は 0 とする
      • それ以外の場合:
        • l を 1 から f まで繰り返し、j − l > 0 であれば dp[i, j] := dp[i, j] + dp[i − 1, j − l] を計算し、さらに dp[i, j] := dp[i, j] mod m を適用する
  • 最後に dp[d − 1][t] mod m を返す

アルゴリズムのポイント

このDPにおいて、dp[i][j] は「i番目までのサイコロを使って合計 j を作る方法の数」を表します。最初のサイコロ(i = 0)については、出目 j が 1 以上 f 以下であればちょうど1通りのみ存在します。2個目以降のサイコロでは、直前の状態に各出目 l(1〜f)を加えることで遷移できるため、dp[i−1][j−l] の総和を計算します。また、答えが巨大な数になるのを防ぐため、毎回 10^9 + 7 の剰余を取っている点も重要なポイントです。

Pythonでの実装例

理解を深めるために、以下の実装例を見てみましょう。

class Solution(object):
    def numRollsToTarget(self, d, f, t):
        mod = 1000000000+7
        dp = [[0 for i in range(t+1)] for j in range(d)]
        for i in range(d):
            for j in range(t+1):
                if i == 0:
                    dp[i][j] = 1 if j>=1 and j<=f else 0
                else:
                    for l in range(1,f+1):
                        if j-l>0:
                            dp[i][j]+=dp[i-1][j-l]
                            dp[i][j]%=mod
        return dp[d-1][t] % mod
ob = Solution()
print(ob.numRollsToTarget(2,6,7))

入力

2
6
7

出力

6
  1. Pythonで二分木の合計がkとなるパスの数を数える方法

    問題の概要 二分木と値 k が与えられたとき、あるノードからその子孫へ向かうパスのうち、通過するノードの値の合計がちょうど k と一致するものがいくつ存在するかを求める問題です。 例えば、次のような二分木を考えてみましょう。 このとき k = 5 であれば、出力は 2 となります。条件を満たすパスは [2, 3] と [1, 4] の2つだからです。 解き方のアプローチ:累積和(prefix sum)の活用 この問題は「累積和(prefix sum)」というテクニックを使うことで、全ノードを一度だけ訪問する効率的なアルゴリズムとして解けます。考え方の手順は以下の通りです。 count:マッ

  2. Pythonプログラムで数の偶数の約数の合計を求める方法

    この記事では、以下の問題文に対する解決策について詳しく解説します。 問題文:ある数が与えられたとき、その数のすべての偶数の約数(因子)の合計を求めて表示します。 アプローチ まず、与えられた数が奇数であるかどうかを確認します。奇数には偶数の約数が存在しないため、その場合は 0 を返します。 数が偶数である場合は、実際の計算に進みます。ここでのポイントは、20(つまり1)以外のすべての項を掛け合わせることで、偶数の約数の合計が得られるという点です。 偶数の約数からすべての奇数を取り除くために、20 に相当する「1」を無視します。この処理を行うことで、残るのは偶数の約数のみとなります。なお、2 は