📜  使用动态规划的除数博弈的最优策略

📅  最后修改于: 2021-09-22 10:32:49             🧑  作者: 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


Javascript


输出:
Player B wins