问题陈述:考虑一行n个硬币,值v1。 。 。 vn,其中n为偶数。我们通过交替轮流与对手进行比赛。在每一回合中,玩家执行以下操作K次。
玩家从该行中选择第一个或最后一个硬币,将其从该行中永久删除,并接收该硬币的价值。
确定如果用户先移动,则用户肯定可以赢得的最大可能金额。
注意:对手和用户一样聪明。
例子:
Input : array = {10, 15, 20, 9, 2, 5}, k=2
Output :32
Explanation:
Lets say, user has initially picked 10 and 15.
The value of coins which the user has is 25 and
{20, 9, 2, 5} are remaining in the array.
In the second round, the opponent picks 20 and 9 making his value 29.
In the third round, the user picks 2 and 5 which makes his total value as 32.
Input: array = {10, 15, 20, 9, 2}, k=1
Output: 32
方法:
需要形成一个递归解决方案,并且需要存储子问题的值以计算结果。
以一个例子来得出递归解;
arr = {10,15,20,9,2,5},k = 2
因此,如果用户在第一轮中选择10、15,则数组中将剩下20、9、2、5。
但是,如果用户选择10、5;然后将15、20、9、2留在数组中。
最后,如果用户选择5、2;然后将10、15、20、9留在数组中。
因此,在选择k个元素之后的任何迭代中,将保留长度为nk的连续子数组以用于下一次计算。
因此,可以在以下位置形成递归解决方案:
S(l, r) = (sum(l, r) – sum(l+i, l+i+n-k-1))+(sum(l+i, l+i+n-k-1) – S(l+i, l+i+n-k-1))
where l+i+n-k-1<=r
所选元素的总和Sc =(sum(l,r)– sum(l + i,l + i + nk-1))
现在,对手将执行下一回合,因此
下一步中选择的元素总数=当前数组从l到r的总和–
对手在下一步骤中选择的元素总和等于
Nc=(sum(l+i, l+i+n-k-1) - S(l+i, l+i+n-k-1)).
S(l, r) = Sc + Nc
where,
Nc=(sum(l+i, l+i+n-k-1) - S(l+i, l+i+n-k-1))
Sc=(sum(l, r) - sum(l+i, l+i+n-k-1))
下面是上述方法的实现:
C++
// C++ implementation of the above approach
#include
using namespace std;
#define ll long long int
// Function to return sum of subarray from l to r
ll sum(int arr[], int l, int r)
{
// calculate sum by a loop from l to r
ll s = 0;
for (int i = l; i <= r; i++) {
s += arr[i];
}
return s;
}
// dp to store the values of sub problems
ll dp[101][101][101] = { 0 };
ll solve(int arr[], int l, int r, int k)
{
// if length of the array is less than k
// return the sum
if (r - l + 1 <= k)
return sum(arr, l, r);
// if the value is previously calculated
if (dp[l][r][k])
return dp[l][r][k];
// else calculate the value
ll sum_ = sum(arr, l, r);
ll len_r = (r - l + 1) - k;
ll len = (r - l + 1);
ll ans = 0;
// select all the sub array of length len_r
for (int i = 0; i < len - len_r + 1; i++) {
// get the sum of that sub array
ll sum_sub = sum(arr, i + l, i + l + len_r - 1);
// check if it is the maximum or not
ans = max(ans, (sum_ - sum_sub) + (sum_sub -
solve(arr, i + l, i + l + len_r - 1, k)));
}
// store it in the table
dp[l][r][k] = ans;
return ans;
}
// Driver code
int main()
{
int arr[] = { 10, 15, 20, 9, 2, 5 }, k = 2;
int n = sizeof(arr) / sizeof(int);
memset(dp, 0, sizeof(dp));
cout << solve(arr, 0, n - 1, k);
return 0;
}
Java
// Java implementation of the above approach
class GFG
{
// Function to return sum of subarray from l to r
static int sum(int arr[], int l, int r)
{
// calculate sum by a loop from l to r
int s = 0;
for (int i = l; i <= r; i++)
{
s += arr[i];
}
return s;
}
// dp to store the values of sub problems
static int dp[][][] = new int[101][101][101] ;
static int solve(int arr[], int l, int r, int k)
{
// if length of the array is less than k
// return the sum
if (r - l + 1 <= k)
return sum(arr, l, r);
// if the value is previously calculated
if (dp[l][r][k] != 0)
return dp[l][r][k];
// else calculate the value
int sum_ = sum(arr, l, r);
int len_r = (r - l + 1) - k;
int len = (r - l + 1);
int ans = 0;
// select all the sub array of length len_r
for (int i = 0; i < len - len_r + 1; i++)
{
// get the sum of that sub array
int sum_sub = sum(arr, i + l, i + l + len_r - 1);
// check if it is the maximum or not
ans = Math.max(ans, (sum_ - sum_sub) + (sum_sub -
solve(arr, i + l, i + l + len_r - 1, k)));
}
// store it in the table
dp[l][r][k] = ans;
return ans;
}
// Driver code
public static void main (String[] args)
{
int arr[] = { 10, 15, 20, 9, 2, 5 }, k = 2;
int n = arr.length;
System.out.println(solve(arr, 0, n - 1, k));
}
}
// This code is contributed by AnkitRai01
Python3
# Python3 implementation of the above approach
import numpy as np
# Function to return sum of subarray from l to r
def Sum(arr, l, r) :
# calculate sum by a loop from l to r
s = 0;
for i in range(l, r + 1) :
s += arr[i];
return s;
# dp to store the values of sub problems
dp = np.zeros((101, 101, 101));
def solve(arr, l, r, k) :
# if length of the array is less than k
# return the sum
if (r - l + 1 <= k) :
return Sum(arr, l, r);
# if the value is previously calculated
if (dp[l][r][k]) :
return dp[l][r][k];
# else calculate the value
sum_ = Sum(arr, l, r);
len_r = (r - l + 1) - k;
length = (r - l + 1);
ans = 0;
# select all the sub array of length len_r
for i in range(length - len_r + 1) :
# get the sum of that sub array
sum_sub = Sum(arr, i + l, i + l + len_r - 1);
# check if it is the maximum or not
ans = max(ans, (sum_ - sum_sub) + (sum_sub -
solve(arr, i + l, i + l + len_r - 1, k)));
# store it in the table
dp[l][r][k] = ans;
return ans;
# Driver code
if __name__ == "__main__" :
arr = [ 10, 15, 20, 9, 2, 5 ]; k = 2;
n = len(arr);
print(solve(arr, 0, n - 1, k));
# This code is contributed by AnkitRai01
C#
// C# implementation of the above approach
using System;
class GFG
{
// Function to return sum of subarray from l to r
static int sum(int []arr, int l, int r)
{
// calculate sum by a loop from l to r
int s = 0;
for (int i = l; i <= r; i++)
{
s += arr[i];
}
return s;
}
// dp to store the values of sub problems
static int [,,]dp = new int[101, 101, 101] ;
static int solve(int []arr, int l, int r, int k)
{
// if length of the array is less than k
// return the sum
if (r - l + 1 <= k)
return sum(arr, l, r);
// if the value is previously calculated
if (dp[l, r, k] != 0)
return dp[l, r, k];
// else calculate the value
int sum_ = sum(arr, l, r);
int len_r = (r - l + 1) - k;
int len = (r - l + 1);
int ans = 0;
// select all the sub array of length len_r
for (int i = 0; i < len - len_r + 1; i++)
{
// get the sum of that sub array
int sum_sub = sum(arr, i + l, i + l + len_r - 1);
// check if it is the maximum or not
ans = Math.Max(ans, (sum_ - sum_sub) + (sum_sub -
solve(arr, i + l, i + l + len_r - 1, k)));
}
// store it in the table
dp[l, r, k] = ans;
return ans;
}
// Driver code
public static void Main ()
{
int []arr = { 10, 15, 20, 9, 2, 5 };
int k = 2;
int n = arr.Length;
Console.WriteLine(solve(arr, 0, n - 1, k));
}
}
// This code is contributed by AnkitRai01
32