Saturday, September 21, 2024
Google search engine
HomeLanguagesDynamic ProgrammingProbability of winning in a Die-throw game

Probability of winning in a Die-throw game

Given that 2 players are playing a die-throw game. The game is one player throws a die and he got a point, he can move forward accordingly to the point. All occurrences to get the point have equal probability. Let player1 start a point x and player2 start a point y. Player 1 can receive a point up to A, and Player 2 can receive a point up to B.  When a player in the position p and point got in the die q, he can move forward a minimum of (p+q) and W. The first player to reach W wins the game. Find the probability modulo that player 1 wins if he goes first modulo 998244353.

To find a probability modulo of 998244353. We can represent the probability as an irreducible fraction y/x, then x is indivisible by 998244353. So, there is a unique integer z between 0 and 998244352 such that xz ≡ y(mod998244353). Find this z.

Examples:

Input W = 6, x = 3, y =2, A = 5, B = 4
Output 586363698

Input W = 5, x = 3, y = 2, A = 1, B = 1
Output 0

Approach: This can be solved with the following idea:

This problem can be solved using dynamic programming. Let dpi, j, f be the probability that player1 wins when player1 and player2  are at points i and j respectively, where f=0 if the turn is player1’s and f=1 if player2’s. The sought value is dpA, B, 0. We first consider the value dpi, j, 0. For k=1, 2, …A, player1 moves forward to point min(i+k, W) with equal probability, so  dpi, j, 0 = 1/A∑Ak=1dpmin(i+k, W), j, 1. Similarly, we consider dpi, j, 1  for k = 1, 2, …B, player2 moves forward to point min(j+k, W) with equal probability, so  dpi, j, 0 = 1/A∑Bk=1dpi, min(j+k, W), 0.
By the relations of the DP array above, we can evaluate the DP array in descending order of i and j. We could find the answer using dpN, i, f =1 and dpi, N, f = 0 for i<W, we could find the answer.

Define a 3D DP array dpi, j, f where dpi, j, f is the probability that player 1 wins when player 1 is at position i and player 2 is at position j, and f is 0 if it’s player 1’s turn and 1 if it’s player 2’s turn.

Below are the steps involved in the implementation of the code:

  • Initialize the DP array as follows:
    • Set dpi, j, 0 = 1 if i = N and dpi, j, 1 = 0 if i = N.
    • Set dpi, j, 0 = 0 if j = N and dpi, j, 1 = 1 if j = N.
    • For all other values of i, j, and f, set dpi, j, f = -1 (to indicate that it hasn’t been computed yet).
  • Evaluate the DP array in descending order of i and j, and for each f value (0 for player 1’s turn, 1 for player 2’s turn):
    • If dpi, j, and f have already been computed, skip to the next value.
    • If f = 0 (player 1’s turn), set dpi, j, 0 as follows: 
      •  For k = 1 to A, compute the new position i’ = min(i + k, W).
      • Compute the average of dpi’, j, 1 overall valid i’ values (i.e., i’ ≤ W).
      • Set dpi, j, 0 = that average.
    • If f = 1 (player 2’s turn), set dpi, j, 1 as follows:
      • For k = 1 to B, compute the new position j’ = min(j + k, W).
      • Compute the average of dpi, j’, 0 overall valid j’ values (i.e., j’ ≤ W).
      • Set dpi, j, 1 = that average.
    • The answer to the problem is dpi, j, 0, where i = 0 and j = 0.

Below are the steps involved in the implementation of the code:

C++




// C++ code for the above approach:
#include <iostream>
using namespace std;
 
const int MOD = 998244353;
 
int dp[110][110][2];
 
// Function to find probability
int mdp(int W, int x, int y, int A, int B)
{
 
    // Initialize base cases
    for (int i = 0; i <= W; i++) {
        for (int f = 0; f < 2; f++) {
 
            // Base case 1: if W is
            // reached on one axis, set
            // the value to 1
            dp[W][i][f] = 1;
 
            // Base case 2: if W is reached
            // on the other axis, set the
            // value to 0
            dp[i][W][f] = 0;
        }
    }
 
    // Fill in the DP table
    for (int i = W - 1; i >= 0; i--) {
        for (int j = W - 1; j >= 0; j--) {
            for (int k = 1; k <= A; k++) {
 
                // If going in the x-axis,
                // add the value from the
                // previous cell in
                // the y-axis
                dp[i][j][0] += dp[min(W, i + k)][j][1];
            }
 
            // Take modulo
            dp[i][j][0] %= MOD;
 
            // Multiply by modular
            // inverse of A
            dp[i][j][0] *= 1LL * (MOD - 1) / A;
            dp[i][j][0] %= MOD;
            for (int k = 1; k <= B; k++) {
                dp[i][j][1] += dp[i][min(W, j + k)][0];
            }
 
            // Take modulo
            dp[i][j][1] %= MOD;
            dp[i][j][1] *= 1LL * (MOD - 1) / B;
            dp[i][j][1] %= MOD;
        }
    }
 
    // Output the answer
    return dp[x][y][0];
}
 
// Drivers Code
int main()
{
    int W = 6, x = 3, y = 2, A = 5, B = 4;
 
    // Function call
    cout << mdp(W, x, y, A, B);
    return 0;
}


Java




// JAVA code for the above approach:
 
class GFG {
    static final int MOD = 998244353;
    static int[][][] dp;
 
    // Function to find probability
    static int mdp(int W, int x, int y, int A, int B)
    {
 
        // Initialize the DP table
        dp = new int[W + 1][W + 1][2];
 
        // Initialize base cases
        for (int i = 0; i <= W; i++) {
            for (int f = 0; f < 2; f++) {
 
                // Base case 1: if W is reached on one axis,
                // set the value to 1
                dp[W][i][f] = 1;
 
                // Base case 2: if W is reached on the other
                // axis, set the value to 0
                dp[i][W][f] = 0;
            }
        }
 
        // Fill in the DP table
        for (int i = W - 1; i >= 0; i--) {
            for (int j = W - 1; j >= 0; j--) {
                for (int k = 1; k <= A; k++) {
 
                    // If going in the x-axis, add the value
                    // from the previous cell in the y-axis
                    dp[i][j][0]
                        += dp[Math.min(W, i + k)][j][1];
                }
 
                // Take modulo
                dp[i][j][0] %= MOD;
 
                // Multiply by modular inverse of A
                dp[i][j][0] *= (MOD - 1) / A;
                dp[i][j][0] %= MOD;
 
                for (int k = 1; k <= B; k++) {
                    dp[i][j][1]
                        += dp[i][Math.min(W, j + k)][0];
                }
 
                // Take modulo
                dp[i][j][1] %= MOD;
                dp[i][j][1] *= (MOD - 1) / B;
                dp[i][j][1] %= MOD;
            }
        }
 
        // Output the answer
        return dp[x][y][0];
    }
 
    // Driver code
    public static void main(String[] args)
    {
        int W = 6, x = 3, y = 2, A = 5, B = 4;
 
        // Function call
        System.out.println(mdp(W, x, y, A, B));
    }
}
 
// This code is contributed by shivamgupta310570


C#




// C# code for the above approach:
 
using System;
using System.Collections.Generic;
 
class Program {
    static int MOD = 998244353;
    static int[, , ] dp;
 
    // Function to find probability
    static int mdp(int W, int x, int y, int A, int B)
    {
 
        // Initialize the DP table
        dp = new int[W + 1, W + 1, 2];
 
        // Initialize base cases
        for (int i = 0; i <= W; i++) {
            for (int f = 0; f < 2; f++) {
 
                // Base case 1: if W is reached on one axis,
                // set the value to 1
                dp[W, i, f] = 1;
 
                // Base case 2: if W is reached on the other
                // axis, set the value to 0
                dp[i, W, f] = 0;
            }
        }
 
        // Fill in the DP table
        for (int i = W - 1; i >= 0; i--) {
            for (int j = W - 1; j >= 0; j--) {
                for (int k = 1; k <= A; k++) {
 
                    // If going in the x-axis, add the value
                    // from the previous cell in the y-axis
                    dp[i, j, 0]
                        += dp[Math.Min(W, i + k), j, 1];
                }
 
                // Take modulo
                dp[i, j, 0] %= MOD;
 
                // Multiply by modular inverse of A
                dp[i, j, 0] *= (MOD - 1) / A;
                dp[i, j, 0] %= MOD;
 
                for (int k = 1; k <= B; k++) {
                    dp[i, j, 1]
                        += dp[i, Math.Min(W, j + k), 0];
                }
 
                // Take modulo
                dp[i, j, 1] %= MOD;
                dp[i, j, 1] *= (MOD - 1) / B;
                dp[i, j, 1] %= MOD;
            }
        }
 
        // Output the answer
        return dp[x, y, 0];
    }
 
    // Driver code
    static void Main(string[] args)
    {
        int W = 6, x = 3, y = 2, A = 5, B = 4;
 
        // Function call
        Console.WriteLine(mdp(W, x, y, A, B));
    }
}
 
// This code is contributed by Tapesh(tapeshdua420)


Output

586363698


Time Complexity: O(W2 * A * B)
Auxiliary Space: O(W2)

Feeling lost in the world of random DSA topics, wasting time without progress? It’s time for a change! Join our DSA course, where we’ll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!

RELATED ARTICLES

Most Popular

Recent Comments