Number of Dice Rolls With Target Sum in Python

The problem asks us to find the number of ways to roll d dice (each with f faces) such that the sum equals a target value. We need to return the result modulo 109 + 7.

For example, with 2 dice having 6 faces each and target sum 7, there are 6 ways: (1,6), (2,5), (3,4), (4,3), (5,2), (6,1).

Algorithm Approach

We'll use dynamic programming where dp[i][j] represents the number of ways to achieve sum j using i+1 dice ?

  • Base case: For the first die, there's exactly 1 way to get any sum from 1 to f
  • Transition: For each additional die, we sum up ways from previous dice states
  • Result: dp[d-1][target] gives us the answer

Implementation

def numRollsToTarget(d, f, target):
    mod = 1000000007
    
    # Create DP table: dp[i][j] = ways to get sum j using i+1 dice
    dp = [[0 for _ in range(target + 1)] for _ in range(d)]
    
    # Fill the DP table
    for i in range(d):
        for j in range(target + 1):
            if i == 0:
                # Base case: first die can show values 1 to f
                dp[i][j] = 1 if 1 <= j <= f else 0
            else:
                # For subsequent dice, sum ways from previous dice
                for face_value in range(1, f + 1):
                    if j - face_value > 0:
                        dp[i][j] += dp[i-1][j - face_value]
                        dp[i][j] %= mod
    
    return dp[d-1][target] % mod

# Test the function
result = numRollsToTarget(2, 6, 7)
print("Number of ways:", result)
Number of ways: 6

How It Works

DP Table for d=2, f=6, target=7 Die 1 Die 2 1 2 3 4 5 6 7 1 1 1 1 1 1 0 0 1 2 3 4 5 6 Answer: 6 dp[1][7] = dp[0][6] + dp[0][5] + dp[0][4] + dp[0][3] + dp[0][2] + dp[0][1] = 1+1+1+1+1+1 = 6

Alternative Approach: Space-Optimized

Since we only need the previous row, we can optimize space complexity ?

def numRollsToTarget_optimized(d, f, target):
    mod = 1000000007
    
    # Use only two arrays instead of 2D table
    prev = [0] * (target + 1)
    curr = [0] * (target + 1)
    
    # Initialize first die
    for j in range(1, min(f + 1, target + 1)):
        prev[j] = 1
    
    # Process remaining dice
    for i in range(1, d):
        curr = [0] * (target + 1)
        for j in range(target + 1):
            for face_value in range(1, f + 1):
                if j - face_value > 0:
                    curr[j] += prev[j - face_value]
                    curr[j] %= mod
        prev = curr[:]
    
    return prev[target] % mod

# Test both approaches
print("Original approach:", numRollsToTarget(2, 6, 7))
print("Optimized approach:", numRollsToTarget_optimized(2, 6, 7))
Original approach: 6
Optimized approach: 6

Complexity Analysis

Approach Time Complexity Space Complexity
2D DP Table O(d × target × f) O(d × target)
Space Optimized O(d × target × f) O(target)

Conclusion

The dynamic programming approach efficiently solves the dice roll problem by building up solutions from smaller subproblems. The space-optimized version reduces memory usage while maintaining the same time complexity.

Updated on: 2026-03-25T08:24:20+05:30

931 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements