📜  游戏的最优策略| 2套

📅  最后修改于: 2021-09-17 16:10:41             🧑  作者: Mango

问题陈述:考虑一排 n 个硬币,价值为 v1 。 . . vn,其中 n 是偶数。我们通过交替轮流与对手进行游戏。在每一轮中,玩家从该行中选择第一个或最后一个硬币,将其从该行中永久移除,并获得该硬币的价值。确定如果我们先行动,我们肯定能赢得的最大可能金额。
注意:对手和使用者一样聪明。

让我们通过几个例子来理解这个问题:
1. 5, 3, 7, 10 : 用户收集最大值为 15(10 + 5)
2. 8, 15, 3, 7 : 用户收集最大值为 22(7 + 15)

在每次移动中选择最好的是否会给出最佳解决方案?
不。在第二个例子中,这是游戏的结束方式:

1.
…….用户选择8。
…….对手选择15。
…….用户选择7。
…….对手选择3。
用户收集的总价值为 15(8 + 7)
2.
…….用户选择7。
…….对手选择8。
…….用户选择15。
…….对手选择3。
用户收集的总价值为 22(7 + 15)
因此,如果用户遵循第二个游戏状态,尽管第一个动作不是最好的,但可以收集最大值。

我们已经讨论了一种进行 4 次递归调用的方法。在这篇文章中,讨论了一种进行两次递归调用的新方法。
有两种选择:
1.用户选择价值为 Vi 的第 i 个硬币:对手选择第 (i+1) 个硬币或第 j 个硬币。对手打算选择给用户留下最小价值的硬币。
即用户可以收集值 Vi + (Sum – Vi) – F(i+1, j, Sum – Vi) 其中 Sum 是从索引 i 到 j 的硬币总和。表达式可以简化为 Sum – F(i+1, j, Sum – Vi)

硬币游戏1

2.用户选择价值为 Vj 的第 j 个硬币:对手选择第 i 个硬币或第 (j-1) 个硬币。对手打算选择给用户留下最小价值的硬币。
即用户可以收集值 Vj + (Sum – Vj) – F(i, j-1, Sum – Vj) 其中 Sum 是从索引 i 到 j 的硬币总和。表达式可以简化为 Sum – F(i, j-1, Sum – Vj)

硬币游戏2

以下是基于以上两种选择的递归解决方案。我们取两个选择中的最大值。

F(i, j)  represents the maximum value the user can collect from 
         i'th coin to j'th coin.
arr[]   represents the list of coins

    F(i, j)  = Max(Sum - F(i+1, j, Sum-arr[i]), 
                   Sum - F(i, j-1, Sum-arr[j])) 
Base Case
    F(i, j)  = max(arr[i], arr[j])  If j == i+1

简单的递归解决方案

C++
// C++ program to find out maximum value from a
// given sequence of coins
#include 
using namespace std;
 
int oSRec(int arr[], int i, int j, int sum)
{
    if (j == i + 1)
        return max(arr[i], arr[j]);
 
    // For both of your choices, the opponent
    // gives you total sum minus maximum of
    // his value
    return max((sum - oSRec(arr, i + 1, j, sum - arr[i])),
               (sum - oSRec(arr, i, j - 1, sum - arr[j])));
}
 
// Returns optimal value possible that a player can
// collect from an array of coins of size n. Note
// than n must be even
int optimalStrategyOfGame(int* arr, int n)
{
    int sum = 0;
    sum = accumulate(arr, arr + n, sum);
    return oSRec(arr, 0, n - 1, sum);
}
 
// Driver program to test above function
int main()
{
    int arr1[] = { 8, 15, 3, 7 };
    int n = sizeof(arr1) / sizeof(arr1[0]);
    printf("%d\n", optimalStrategyOfGame(arr1, n));
 
    int arr2[] = { 2, 2, 2, 2 };
    n = sizeof(arr2) / sizeof(arr2[0]);
    printf("%d\n", optimalStrategyOfGame(arr2, n));
 
    int arr3[] = { 20, 30, 2, 2, 2, 10 };
    n = sizeof(arr3) / sizeof(arr3[0]);
    printf("%d\n", optimalStrategyOfGame(arr3, n));
 
    return 0;
}


Java
// Java program to find out maximum value from a
// given sequence of coins
import java .io.*;
 
class GFG
{
 
    static int oSRec(int []arr, int i, int j, int sum)
    {
        if (j == i + 1)
            return Math.max(arr[i], arr[j]);
     
        // For both of your choices, the opponent
        // gives you total sum minus maximum of
        // his value
        return Math.max((sum - oSRec(arr, i + 1, j, sum - arr[i])),
                (sum - oSRec(arr, i, j - 1, sum - arr[j])));
    }
     
    // Returns optimal value possible that a player can
    // collect from an array of coins of size n. Note
    // than n must be even
    static int optimalStrategyOfGame(int[] arr, int n)
    {
        int sum = 0;
        for(int i = 0; i < n; i++)
        {
            sum += arr[i];
        }
 
        return oSRec(arr, 0, n - 1, sum);
    }
     
    // Driver code
    static public void main (String[] args)
    {
        int []arr1 = { 8, 15, 3, 7 };
        int n = arr1.length;
        System.out.println(optimalStrategyOfGame(arr1, n));
     
        int []arr2 = { 2, 2, 2, 2 };
        n = arr2.length;
        System.out.println(optimalStrategyOfGame(arr2, n));
     
        int []arr3 = { 20, 30, 2, 2, 2, 10 };
        n = arr3.length ;
        System.out.println(optimalStrategyOfGame(arr3, n));
    }
}
 
// This code is contributed by anuj_67..


Python3
# python3 program to find out maximum value from a
# given sequence of coins
 
def oSRec (arr, i, j, Sum):
 
    if (j == i + 1):
        return max(arr[i], arr[j])
 
    # For both of your choices, the opponent
    # gives you total Sum minus maximum of
    # his value
    return max((Sum - oSRec(arr, i + 1, j, Sum - arr[i])),
                (Sum - oSRec(arr, i, j - 1, Sum - arr[j])))
 
# Returns optimal value possible that a player can
# collect from an array of coins of size n. Note
# than n must be even
def optimalStrategyOfGame(arr, n):
 
    Sum = 0
    Sum = sum(arr)
    return oSRec(arr, 0, n - 1, Sum)
 
# Driver code
 
arr1= [ 8, 15, 3, 7]
n = len(arr1)
print(optimalStrategyOfGame(arr1, n))
 
arr2= [ 2, 2, 2, 2 ]
n = len(arr2)
print(optimalStrategyOfGame(arr2, n))
 
arr3= [ 20, 30, 2, 2, 2, 10 ]
n = len(arr3)
print(optimalStrategyOfGame(arr3, n))
 
# This code is contributed by Mohit kumar 29


C#
// C# program to find out maximum value from a
// given sequence of coins
using System;
class GFG
{
    static int oSRec(int []arr, int i,
                     int j, int sum)
    {
        if (j == i + 1)
            return Math.Max(arr[i], arr[j]);
     
        // For both of your choices, the opponent
        // gives you total sum minus maximum of
        // his value
        return Math.Max((sum - oSRec(arr, i + 1, j,
                                     sum - arr[i])),
                        (sum - oSRec(arr, i, j - 1,
                                     sum - arr[j])));
    }
     
    // Returns optimal value possible that a player can
    // collect from an array of coins of size n. Note
    // than n must be even
    static int optimalStrategyOfGame(int[] arr, int n)
    {
        int sum = 0;
        for(int i = 0; i < n; i++)
        {
            sum += arr[i];
        }
 
        return oSRec(arr, 0, n - 1, sum);
    }
     
    // Driver code
    static public void Main ()
    {
        int []arr1 = { 8, 15, 3, 7 };
        int n = arr1.Length;
        Console.WriteLine(optimalStrategyOfGame(arr1, n));
     
        int []arr2 = { 2, 2, 2, 2 };
        n = arr2.Length;
        Console.WriteLine(optimalStrategyOfGame(arr2, n));
     
        int []arr3 = { 20, 30, 2, 2, 2, 10 };
        n = arr3.Length;
        Console.WriteLine(optimalStrategyOfGame(arr3, n));
    }
}
 
// This code is contributed by AnkitRai01


Javascript


C++
// C++ program to find out maximum value from a
// given sequence of coins
#include 
using namespace std;
 
const int MAX = 100;
 
int memo[MAX][MAX];
 
int oSRec(int arr[], int i, int j, int sum)
{
    if (j == i + 1)
        return max(arr[i], arr[j]);
 
    if (memo[i][j] != -1)
        return memo[i][j];
 
    // For both of your choices, the opponent
    // gives you total sum minus maximum of
    // his value
    memo[i][j] = max((sum - oSRec(arr, i + 1, j, sum - arr[i])),
                     (sum - oSRec(arr, i, j - 1, sum - arr[j])));
 
    return memo[i][j];
}
 
// Returns optimal value possible that a player can
// collect from an array of coins of size n. Note
// than n must be even
int optimalStrategyOfGame(int* arr, int n)
{
    // Compute sum of elements
    int sum = 0;
    sum = accumulate(arr, arr + n, sum);
 
    // Initialize memoization table
    memset(memo, -1, sizeof(memo));
 
    return oSRec(arr, 0, n - 1, sum);
}
 
// Driver program to test above function
int main()
{
    int arr1[] = { 8, 15, 3, 7 };
    int n = sizeof(arr1) / sizeof(arr1[0]);
    printf("%d\n", optimalStrategyOfGame(arr1, n));
 
    int arr2[] = { 2, 2, 2, 2 };
    n = sizeof(arr2) / sizeof(arr2[0]);
    printf("%d\n", optimalStrategyOfGame(arr2, n));
 
    int arr3[] = { 20, 30, 2, 2, 2, 10 };
    n = sizeof(arr3) / sizeof(arr3[0]);
    printf("%d\n", optimalStrategyOfGame(arr3, n));
 
    return 0;
}


Java
// Java program to find out maximum value from a
// given sequence of coins
import java.util.*;
class GFG{
 
static int MAX = 100;
 
static int [][]memo = new int[MAX][MAX];
 
static int oSRec(int arr[], int i,
                 int j, int sum)
{
    if (j == i + 1)
        return Math.max(arr[i], arr[j]);
 
    if (memo[i][j] != -1)
        return memo[i][j];
 
    // For both of your choices, the opponent
    // gives you total sum minus maximum of
    // his value
    memo[i][j] = Math.max((sum - oSRec(arr, i + 1, j,
                                       sum - arr[i])),
                           (sum - oSRec(arr, i, j - 1,
                                       sum - arr[j])));
 
    return memo[i][j];
}
 
static int accumulate(int[] arr,
                      int start, int end)
{
    int sum=0;
    for(int i= 0; i < arr.length; i++)
        sum += arr[i];
    return sum;
}
   
// Returns optimal value possible that a player can
// collect from an array of coins of size n. Note
// than n must be even
static int optimalStrategyOfGame(int []arr, int n)
{
    // Compute sum of elements
    int sum = 0;
    sum = accumulate(arr, 0, n);
 
    // Initialize memoization table
    for (int j = 0; j < MAX; j++)
    {
        for (int k = 0; k < MAX; k++)
            memo[j][k] = -1;
    }
 
    return oSRec(arr, 0, n - 1, sum);
}
 
// Driver Code
public static void main(String[] args)
{
    int arr1[] = { 8, 15, 3, 7 };
    int n = arr1.length;
    System.out.printf("%d\n",
               optimalStrategyOfGame(arr1, n));
 
    int arr2[] = { 2, 2, 2, 2 };
    n = arr2.length;
    System.out.printf("%d\n",
               optimalStrategyOfGame(arr2, n));
 
    int arr3[] = { 20, 30, 2, 2, 2, 10 };
    n = arr3.length;
    System.out.printf("%d\n",
               optimalStrategyOfGame(arr3, n));
}
}
 
// This code is contributed by gauravrajput1


Python3
# Python3 program to find out maximum value
# from a given sequence of coins
MAX = 100
  
memo = [[0 for i in range(MAX)]
           for j in range(MAX)]
  
def oSRec(arr, i, j, Sum):
 
    if (j == i + 1):
        return max(arr[i], arr[j])
  
    if (memo[i][j] != -1):
        return memo[i][j]
  
    # For both of your choices, the opponent
    # gives you total sum minus maximum of
    # his value
    memo[i][j] = max((Sum - oSRec(arr, i + 1, j,
                                     Sum - arr[i])),
                     (Sum - oSRec(arr, i, j - 1,
                                        Sum - arr[j])))
  
    return memo[i][j]
    
# Returns optimal value possible that a
# player can collect from an array of
# coins of size n. Note than n must
# be even
def optimalStrategyOfGame(arr, n):
 
    # Compute sum of elements
    Sum = 0
    Sum = sum(arr)
  
    # Initialize memoization table
    for j in range(MAX):
        for k in range(MAX):
            memo[j][k] = -1
  
    return oSRec(arr, 0, n - 1, Sum)
  
# Driver Code
arr1 = [ 8, 15, 3, 7 ]
n = len(arr1)
print(optimalStrategyOfGame(arr1, n))
 
arr2 = [ 2, 2, 2, 2 ]
n = len(arr2)
print(optimalStrategyOfGame(arr2, n))
 
arr3 = [ 20, 30, 2, 2, 2, 10 ]
n = len(arr3)
print(optimalStrategyOfGame(arr3, n))
 
# This code is contributed by divyesh072019


C#
// C# program to find out maximum value from a
// given sequence of coins
using System;
class GFG{
 
  static int MAX = 100;
 
  static int[,] memo = new int[MAX, MAX];
 
  static int oSRec(int []arr, int i,
                   int j, int sum)
  {
    if (j == i + 1)
      return Math.Max(arr[i], arr[j]);
 
    if (memo[i, j] != -1)
      return memo[i, j];
 
    // For both of your choices, the opponent
    // gives you total sum minus maximum of
    // his value
    memo[i, j] = Math.Max((sum - oSRec(arr, i + 1, j,
                                       sum - arr[i])),
                          (sum - oSRec(arr, i, j - 1,
                                       sum - arr[j])));
 
    return memo[i,j];
  }
 
  static int accumulate(int[] arr, int start,
                        int end)
  {
    int sum = 0;
    for (int i = 0; i < arr.Length; i++)
      sum += arr[i];
    return sum;
  }
 
  // Returns optimal value possible that a player can
  // collect from an array of coins of size n. Note
  // than n must be even
  static int optimalStrategyOfGame(int[] arr, int n)
  {
    // Compute sum of elements
    int sum = 0;
    sum = accumulate(arr, 0, n);
 
    // Initialize memoization table
    for (int j = 0; j < MAX; j++)
    {
      for (int k = 0; k < MAX; k++)
        memo[j, k] = -1;
    }
 
    return oSRec(arr, 0, n - 1, sum);
  }
 
  // Driver Code
  public static void Main(String[] args)
  {
    int []arr1 = { 8, 15, 3, 7 };
    int n = arr1.Length;
    Console.Write("{0}\n", optimalStrategyOfGame(arr1, n));
 
    int []arr2 = { 2, 2, 2, 2 };
    n = arr2.Length;
    Console.Write("{0}\n", optimalStrategyOfGame(arr2, n));
 
    int []arr3 = { 20, 30, 2, 2, 2, 10 };
    n = arr3.Length;
    Console.Write("{0}\n", optimalStrategyOfGame(arr3, n));
  }
}
 
// This code is contributed by Rohit_ranjan


Javascript


输出:
22
4
42

基于记忆的解决方案

C++

// C++ program to find out maximum value from a
// given sequence of coins
#include 
using namespace std;
 
const int MAX = 100;
 
int memo[MAX][MAX];
 
int oSRec(int arr[], int i, int j, int sum)
{
    if (j == i + 1)
        return max(arr[i], arr[j]);
 
    if (memo[i][j] != -1)
        return memo[i][j];
 
    // For both of your choices, the opponent
    // gives you total sum minus maximum of
    // his value
    memo[i][j] = max((sum - oSRec(arr, i + 1, j, sum - arr[i])),
                     (sum - oSRec(arr, i, j - 1, sum - arr[j])));
 
    return memo[i][j];
}
 
// Returns optimal value possible that a player can
// collect from an array of coins of size n. Note
// than n must be even
int optimalStrategyOfGame(int* arr, int n)
{
    // Compute sum of elements
    int sum = 0;
    sum = accumulate(arr, arr + n, sum);
 
    // Initialize memoization table
    memset(memo, -1, sizeof(memo));
 
    return oSRec(arr, 0, n - 1, sum);
}
 
// Driver program to test above function
int main()
{
    int arr1[] = { 8, 15, 3, 7 };
    int n = sizeof(arr1) / sizeof(arr1[0]);
    printf("%d\n", optimalStrategyOfGame(arr1, n));
 
    int arr2[] = { 2, 2, 2, 2 };
    n = sizeof(arr2) / sizeof(arr2[0]);
    printf("%d\n", optimalStrategyOfGame(arr2, n));
 
    int arr3[] = { 20, 30, 2, 2, 2, 10 };
    n = sizeof(arr3) / sizeof(arr3[0]);
    printf("%d\n", optimalStrategyOfGame(arr3, n));
 
    return 0;
}

Java

// Java program to find out maximum value from a
// given sequence of coins
import java.util.*;
class GFG{
 
static int MAX = 100;
 
static int [][]memo = new int[MAX][MAX];
 
static int oSRec(int arr[], int i,
                 int j, int sum)
{
    if (j == i + 1)
        return Math.max(arr[i], arr[j]);
 
    if (memo[i][j] != -1)
        return memo[i][j];
 
    // For both of your choices, the opponent
    // gives you total sum minus maximum of
    // his value
    memo[i][j] = Math.max((sum - oSRec(arr, i + 1, j,
                                       sum - arr[i])),
                           (sum - oSRec(arr, i, j - 1,
                                       sum - arr[j])));
 
    return memo[i][j];
}
 
static int accumulate(int[] arr,
                      int start, int end)
{
    int sum=0;
    for(int i= 0; i < arr.length; i++)
        sum += arr[i];
    return sum;
}
   
// Returns optimal value possible that a player can
// collect from an array of coins of size n. Note
// than n must be even
static int optimalStrategyOfGame(int []arr, int n)
{
    // Compute sum of elements
    int sum = 0;
    sum = accumulate(arr, 0, n);
 
    // Initialize memoization table
    for (int j = 0; j < MAX; j++)
    {
        for (int k = 0; k < MAX; k++)
            memo[j][k] = -1;
    }
 
    return oSRec(arr, 0, n - 1, sum);
}
 
// Driver Code
public static void main(String[] args)
{
    int arr1[] = { 8, 15, 3, 7 };
    int n = arr1.length;
    System.out.printf("%d\n",
               optimalStrategyOfGame(arr1, n));
 
    int arr2[] = { 2, 2, 2, 2 };
    n = arr2.length;
    System.out.printf("%d\n",
               optimalStrategyOfGame(arr2, n));
 
    int arr3[] = { 20, 30, 2, 2, 2, 10 };
    n = arr3.length;
    System.out.printf("%d\n",
               optimalStrategyOfGame(arr3, n));
}
}
 
// This code is contributed by gauravrajput1

蟒蛇3

# Python3 program to find out maximum value
# from a given sequence of coins
MAX = 100
  
memo = [[0 for i in range(MAX)]
           for j in range(MAX)]
  
def oSRec(arr, i, j, Sum):
 
    if (j == i + 1):
        return max(arr[i], arr[j])
  
    if (memo[i][j] != -1):
        return memo[i][j]
  
    # For both of your choices, the opponent
    # gives you total sum minus maximum of
    # his value
    memo[i][j] = max((Sum - oSRec(arr, i + 1, j,
                                     Sum - arr[i])),
                     (Sum - oSRec(arr, i, j - 1,
                                        Sum - arr[j])))
  
    return memo[i][j]
    
# Returns optimal value possible that a
# player can collect from an array of
# coins of size n. Note than n must
# be even
def optimalStrategyOfGame(arr, n):
 
    # Compute sum of elements
    Sum = 0
    Sum = sum(arr)
  
    # Initialize memoization table
    for j in range(MAX):
        for k in range(MAX):
            memo[j][k] = -1
  
    return oSRec(arr, 0, n - 1, Sum)
  
# Driver Code
arr1 = [ 8, 15, 3, 7 ]
n = len(arr1)
print(optimalStrategyOfGame(arr1, n))
 
arr2 = [ 2, 2, 2, 2 ]
n = len(arr2)
print(optimalStrategyOfGame(arr2, n))
 
arr3 = [ 20, 30, 2, 2, 2, 10 ]
n = len(arr3)
print(optimalStrategyOfGame(arr3, n))
 
# This code is contributed by divyesh072019

C#

// C# program to find out maximum value from a
// given sequence of coins
using System;
class GFG{
 
  static int MAX = 100;
 
  static int[,] memo = new int[MAX, MAX];
 
  static int oSRec(int []arr, int i,
                   int j, int sum)
  {
    if (j == i + 1)
      return Math.Max(arr[i], arr[j]);
 
    if (memo[i, j] != -1)
      return memo[i, j];
 
    // For both of your choices, the opponent
    // gives you total sum minus maximum of
    // his value
    memo[i, j] = Math.Max((sum - oSRec(arr, i + 1, j,
                                       sum - arr[i])),
                          (sum - oSRec(arr, i, j - 1,
                                       sum - arr[j])));
 
    return memo[i,j];
  }
 
  static int accumulate(int[] arr, int start,
                        int end)
  {
    int sum = 0;
    for (int i = 0; i < arr.Length; i++)
      sum += arr[i];
    return sum;
  }
 
  // Returns optimal value possible that a player can
  // collect from an array of coins of size n. Note
  // than n must be even
  static int optimalStrategyOfGame(int[] arr, int n)
  {
    // Compute sum of elements
    int sum = 0;
    sum = accumulate(arr, 0, n);
 
    // Initialize memoization table
    for (int j = 0; j < MAX; j++)
    {
      for (int k = 0; k < MAX; k++)
        memo[j, k] = -1;
    }
 
    return oSRec(arr, 0, n - 1, sum);
  }
 
  // Driver Code
  public static void Main(String[] args)
  {
    int []arr1 = { 8, 15, 3, 7 };
    int n = arr1.Length;
    Console.Write("{0}\n", optimalStrategyOfGame(arr1, n));
 
    int []arr2 = { 2, 2, 2, 2 };
    n = arr2.Length;
    Console.Write("{0}\n", optimalStrategyOfGame(arr2, n));
 
    int []arr3 = { 20, 30, 2, 2, 2, 10 };
    n = arr3.Length;
    Console.Write("{0}\n", optimalStrategyOfGame(arr3, n));
  }
}
 
// This code is contributed by Rohit_ranjan

Javascript


输出:
22
4
42

这种方法是由Alind建议的。

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程