问题: 有一个由N块砖组成的堆栈。你和你的朋友决定使用这个堆栈玩游戏。在这个游戏中,人们可以从顶部移除1/2/3砖块,并将玩家移除的砖块上的数字添加到他的分数中。你必须以这样一种方式进行游戏,即你获得最大可能的分数,同时你的朋友也会以最佳方式进行游戏,并且你是第一步。
输入格式 第一行将包含整数T,即测试用例的数量。对应于每个测试用例将有两行,第一行将包含一个数字N,即堆栈中的元素数量,下一行将包含N个数字,即从上到下写在砖块上的数字。
输出格式 对于每个测试用例,打印包含最高分数的单行。 我尝试了递归但没有工作
int recurse(int length, int sequence[5], int i) {
if(length - i < 3) {
int sum = 0;
for(i; i < length; i++) sum += sequence[i];
return sum;
} else {
int sum1 = 0;
int sum2 = 0;
int sum3 = 0;
sum1 += recurse(length, sequence, i+1);
sum2 += recurse(length, sequence, i+2);
sum3 += recurse(length, sequence, i+3);
return max(max(sum1,sum2),sum3);
}
}
int main() {
int sequence[] = {0, 0, 9, 1, 999};
int length = 5;
cout << recurse(length, sequence, 0);
return 0;
}
答案 0 :(得分:2)
我解决这个问题的方法如下:
因此,解决方案的构建方式不需要考虑玩家。这是因为对于任何给定状态的砖块,两位球员都会选择最适合他们的选择。
任何一个玩家,当留下最后一个/两个/三个砖块时,将选择移除所有砖块。
为了方便起见,我们假设数组实际上是以相反的顺序排列(即[0]是堆栈中最底部砖块的值)(这可以通过执行来轻松实现)对阵列进行反向操作。)
所以,基本案例是:
bclass
现在,在每次迭代中,玩家有3个选择。
如果玩家选择了选项1,则会产生以下结果:
用于存储砖块的部分和的前缀数组可以如下计算:
# Base Cases
dp[0] = a[0]
dp[1] = a[0]+a[1]
dp[2] = a[0]+a[1]+a[2]
而且,现在,如果玩家选择了选择1,则得分为:
# build prefix sum array
pre = [a[0]]
for i in range(1,n):
pre.append(pre[-1]+a[i])
同样,对于选择2和3.因此,我们得到:
ans1 = a[i] + (pre[i-1] - dp[i-1])
现在,每位玩家都希望最大化此值。因此,在每次迭代中,我们选择ans1,ans2和ans3中的最大值。 dp [i] = max(ans1,ans2,ans3)
现在,我们所要做的就是从3迭代到n-1以获得所需的解决方案。
以下是python中的最终片段:
ans1 = a[i]+ (pre[i-1] - dp[i-1]) # if we pick only ith brick
ans2 = a[i]+a[i-1]+(pre[i-2] - dp[i-2]) # pick 2 bricks
ans3 = a[i]+a[i-1]+a[i-2]+(pre[i-3] - dp[i-3]) # pick 3 bricks
答案 1 :(得分:1)
乍一看,由于以下几个原因,您的代码似乎完全错误:
不考虑玩家。你拿砖头或你的朋友拿砖不一样(你最大化你的得分,总数当然总是砖块上的得分总和)。
看起来只是某种形式的递归,没有任何记忆,这种方法显然会爆炸到指数计算时间(你正在使用&#34;暴力&#34;方法,枚举所有可能的游戏)。
动态编程方法显然是可行的,因为游戏的最佳延续并不取决于你是如何达到某个状态的。对于你需要的游戏状态
通过这两个输入,您可以计算从该点到游戏结束时可以收集多少。要做到这一点有两种情况
你需要尝试收集1,2或3并在下一个对手必须选择的游戏状态下递归调用。在这三种情况中,你保留了最高的结果
您需要模拟1,2或3块砖的集合,并在您必须选择的下一个游戏状态下递归调用。在这三种情况中你保持最低结果(因为对手试图最大化他/她的结果,而不是你的结果)。
在函数的最开始,您只需要检查之前是否处理过相同的游戏状态,并且从计算返回时需要存储结果。由于这种查找/记忆,搜索时间不是指数级的,而是在不同游戏状态的数量上呈线性(只有2 * N,其中N是砖的数量)。
在Python中:
memory = {}
bricks = [0, 0, 9, 1, 999]
def maxResult(my_turn, index):
key = (my_turn, index)
if key in memory:
return memory[key]
if index == len(bricks):
result = 0
elif my_turn:
result = None
s = 0
for i in range(index, min(index+3, len(bricks))):
s += bricks[i]
x = s + maxResult(False, i+1)
if result is None or x > result:
result = x
else:
result = None
for i in range(index, min(index+3, len(bricks))):
x = maxResult(True, i+1)
if result is None or x < result:
result = x
memory[key] = result
return result
print maxResult(True, 0)
答案 2 :(得分:1)
import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
public class Solution {
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int noTest=sc.nextInt();
for(int i=0; i<noTest; i++){
int noBrick=sc.nextInt();
ArrayList<Integer> arr=new ArrayList<Integer>();
for (int j=0; j<noBrick; j++){
arr.add(sc.nextInt());
}
long sum[]= new long[noBrick];
sum[noBrick-1]= arr.get(noBrick-1);
for (int j=noBrick-2; j>=0; j--){
sum[j]= sum[j+1]+ arr.get(j);
}
long[] max=new long[noBrick];
if(noBrick>=1)
max[noBrick-1]=arr.get(noBrick-1);
if(noBrick>=2)
max[noBrick-2]=(int)Math.max(arr.get(noBrick-2),max[noBrick-1]+arr.get(noBrick-2));
if(noBrick>=3)
max[noBrick-3]=(int)Math.max(arr.get(noBrick-3),max[noBrick-2]+arr.get(noBrick-3));
if(noBrick>=4){
for (int j=noBrick-4; j>=0; j--){
long opt1= arr.get(j)+sum[j+1]-max[j+1];
long opt2= arr.get(j)+arr.get(j+1)+sum[j+2]-max[j+2];
long opt3= arr.get(j)+arr.get(j+1)+arr.get(j+2)+sum[j+3]-max[j+3];
max[j]= (long)Math.max(opt1,Math.max(opt2,opt3));
}
}
long cost= max[0];
System.out.println(cost);
}
}
}
我尝试使用Java,似乎工作正常。
答案 3 :(得分:0)
这是一个更好的解决方案,我在互联网上找到没有递归。
#include <iostream>
#include <fstream>
#include <algorithm>
#define MAXINDEX 10001
using namespace std;
long long maxResult(int a[MAXINDEX], int LENGTH){
long long prefixSum [MAXINDEX] = {0};
prefixSum[0] = a[0];
for(int i = 1; i < LENGTH; i++){
prefixSum[i] += prefixSum[i-1] + a[i];
}
long long dp[MAXINDEX] = {0};
dp[0] = a[0];
dp[1] = dp[0] + a[1];
dp[2] = dp[1] + a[2];
for(int k = 3; k < LENGTH; k++){
long long x = prefixSum[k-1] + a[k] - dp[k-1];
long long y = prefixSum[k-2] + a[k] + a[k-1] - dp[k-2];
long long z = prefixSum[k-3] + a[k] + a[k-1] + a[k-2] - dp[k-3];
dp[k] = max(x,max(y,z));
}
return dp[LENGTH-1];
}
using namespace std;
int main(){
int cases;
int bricks[MAXINDEX];
ifstream fin("test.in");
fin >> cases;
for (int i = 0; i < cases; i++){
long n;
fin >> n;
for(int j = 0; j < n; j++) fin >> bricks[j];
reverse(bricks, bricks+n);
cout << maxResult(bricks, n)<< endl;
}
return 0;
}