📜  使用动态规划的除数游戏的最佳策略

📅  最后修改于: 2021-05-17 21:45:26             🧑  作者: Mango

给定一个整数N和两个玩家,A和B正在玩游戏。在每个玩家的回合中,该玩家通过从当前N减去当前N的除数(小于N)来进行移动,从而为下一回合形成新的N。剩下没有除数的玩家将输掉比赛。任务是,假设两个玩家都玩得最好,那么如果玩家A进行了第一回合,则告诉哪个玩家赢得了比赛。

例子:

方法 :

上面提到的这个问题可以使用动态编程来解决

  • 我们将选择一个具有2个状态的DP,即
  • 在每个州,我们将尝试找到N的所有除数,并尝试找到当前玩家获胜的下一个州。对于玩家A,我们将尝试找到返回值为true的下一个状态,而对于玩家B,我们将尝试找到返回值为false的下一个状态(因为false表示玩家A的损失)。
  • 基本情况是对于N = 1,总是玩家A输掉比赛,而N = 2,总是玩家B输掉比赛。
  • 为了找到答案,我们只需要找到DP [N] [1]的值即可。

下面是上述方法的实现:

C++
// C++ program for implementation of
// Optimal Strategy for the Divisor
// Game using Dynamic Programming
#include 
using namespace std;
  
// Recursive function to find the winner
bool divisorGame(int N, bool A, int dp[][2])
{
  
    // check if N=1 or N=3 then player B wins
    if (N == 1 or N == 3)
        return false;
  
    // check if N=2 then player A wins
    if (N == 2)
        return true;
  
    // check if current state already visited
    // then return the previously obtained ans
    if (dp[N][A] != -1)
        return dp[N][A];
  
    // check if currently it is player A's turn
    // then initialise the ans to 0
    int ans = (A == 1) ? 0 : 1;
  
    // Traversing across all the divisors of N
    // which are less than N
    for (int i = 1; i * i <= N; i++) {
  
        // check if current value of
        // i is a divisor of N
        if (N % i == 0) {
  
            // check if it is player A's turn
            // then we need at least one true
            if (A)
                ans |= divisorGame(N - i, 0, dp);
  
            // Else if it is player B's turn
            // then we need at least one false
            else
                ans &= divisorGame(N - i, 1, dp);
        }
    }
  
    // Return the current ans
    return dp[N][A] = ans;
}
  
// Driver code
int main()
{
    // initialise N
    int N = 3;
  
    int dp[N + 1][2];
  
    memset(dp, -1, sizeof(dp));
  
    if (divisorGame(N, 1, dp) == true)
        cout << "Player A wins";
    else
        cout << "Player B wins";
  
    return 0;
}


Java
// Java program for implementation of
// optimal strategy for the divisor
// game using dynamic programming
  
import java.util.*;
  
class GFG {
  
    // Recursive function to find the winner
    static int divisorGame(int N, int A, int dp[][]) {
  
        // Check if N = 1 or N = 3 then player B wins
        if (N == 1 || N == 3)
            return 0;
  
        // Check if N = 2 then player A wins
        if (N == 2)
            return 1;
  
        // Check if current state already visited
        // then return the previously obtained ans
        if (dp[N][A] != -1)
            return dp[N][A];
  
        // Check if currently it is player A's turn
        // then initialise the ans to 0
        int ans = (A == 1) ? 0 : 1;
  
        // Traversing across all the divisors of N
        // which are less than N
        for (int i = 1; i * i <= N; i++) {
  
            // Check if current value of
            // i is a divisor of N
            if (N % i == 0) {
  
                // Check if it is player A's turn
                // then we need at least one true
                if (A == 1)
                    ans |= divisorGame(N - i, 0, dp);
  
                // Else if it is player B's turn
                // then we need at least one false
                else
                   ans &= divisorGame(N - i, 1, dp);
            }
        }
  
        // Return the current ans
        return dp[N][A] = ans;
    }
  
    // Driver code
    public static void main(String[] args) {
          
        // Initialise N
        int N = 3;
  
        int[][] dp = new int[N + 1][2];
  
        for (int i = 0; i < N + 1; i++) {
             for (int j = 0; j < 2; j++) {
                  dp[i][j] = -1;
            }
        }
  
        if (divisorGame(N, 1, dp) == 1)
            System.out.print("Player A wins");
        else
            System.out.print("Player B wins");
  
    }
}
  
// This code contributed by sapnasingh4991


Python3
# Python3 program for implementation of
# Optimal Strategy for the Divisor
# Game using Dynamic Programming
  
from math import sqrt
  
# Recursive function to find the winner
def divisorGame(N,A,dp):
    # check if N=1 or N=3 then player B wins
    if (N == 1 or N == 3):
        return False
  
    # check if N=2 then player A wins
    if (N == 2):
        return True
  
    # check if current state already visited
    # then return the previously obtained ans
    if (dp[N][A] != -1):
        return dp[N][A]
  
    # check if currently it is player A's turn
    # then initialise the ans to 0
    if(A == 1):
        ans = 0
    else:
        ans = 1
  
    # Traversing across all the divisors of N
    # which are less than N
    for i in range(1,int(sqrt(N))+1,1):
        # check if current value of
        # i is a divisor of N
        if (N % i == 0):
            # check if it is player A's turn
            # then we need at least one true
            if (A):
                ans |= divisorGame(N - i, 0, dp)
  
            # Else if it is player B's turn
            # then we need at least one false
            else:
                ans &= divisorGame(N - i, 1, dp) 
  
    dp[N][A] = ans
  
  
    # Return the current ans
    return dp[N][A]
  
# Driver code
if __name__ == '__main__':
    # initialise N
    N = 3
  
    dp = [[-1 for i in range(2)] for j in range(N+1)]
  
    if (divisorGame(N, 1, dp) == True):
        print("Player A wins")
    else:
        print("Player B wins")
  
# This code is contributed by Surendra_Gangwar


C#
// C# program for implementation of
// optimal strategy for the divisor
// game using dynamic programming
using System;
  
class GFG {
  
// Recursive function to find the winner
static int divisorGame(int N, int A, 
                       int [,]dp)
{
  
    // Check if N = 1 or N = 3 
    // then player B wins
    if (N == 1 || N == 3)
        return 0;
  
    // Check if N = 2 then player A wins
    if (N == 2)
        return 1;
  
    // Check if current state already visited
    // then return the previously obtained ans
    if (dp[N, A] != -1)
        return dp[N, A];
  
    // Check if currently it is player A's turn
    // then initialise the ans to 0
    int ans = (A == 1) ? 0 : 1;
  
    // Traversing across all the divisors of N
    // which are less than N
    for(int i = 1; i * i <= N; i++)
    {
          
       // Check if current value of
       // i is a divisor of N
       if (N % i == 0)
       {
             
           // Check if it is player A's turn
           // then we need at least one true
           if (A == 1)
               ans |= divisorGame(N - i, 0, dp);
                 
           // Else if it is player B's turn
           // then we need at least one false
           else
              ans &= divisorGame(N - i, 1, dp);
       }
    }
      
    // Return the current ans
    return dp[N, A] = ans;
}
  
// Driver code
public static void Main(String[] args)
{
      
    // Initialise N
    int N = 3;
    int[,] dp = new int[N + 1, 2];
      
    for(int i = 0; i < N + 1; i++) 
    {
       for(int j = 0; j < 2; j++) 
       {
          dp[i, j] = -1;
       }
    }
      
    if (divisorGame(N, 1, dp) == 1)
    {
        Console.Write("Player A wins");
    }
    else
    {
        Console.Write("Player B wins");
    }
}
}
  
// This code is contributed by amal kumar choubey


输出:
Player B wins