方法一:枚举+记录历史结果
每次操作有3种选择,选择1个,选择2个,选择3个。枚举这3种操作,然后选择最优选择,就是比对方的分数越多越好。
选择了后,轮到对方选择(这里选择是枚举),不断循环,直到,剩下两个或一个。只有两个的情况下,判断第二个是否大于0,大于0要,小于0留给对方。只有1个的情况下,按照游戏规则,必须选择这一个。然后返回去,按照对手的最优选择结果来计算自己的结果。
记录历史结果,由于两个选手是对称的,对于同一个开始位置(一系列数字),得到的最优选择都是同样的,和结果无关,所以我们记录这个开始位置的结果。
class Solution {
public:
int n;
int record[2];
int cache[50005][2];
void select(const vector<int>& stoneValue ,int start,int mode){
if(start>=n){
return;
}
int other_mode=mode==0?1:0;
if(cache[start][0]!=-1 && cache[start][1]!=-1){
record[mode]=cache[start][0];
record[other_mode]=cache[start][1];
return;
}
if(n-start==1){
record[mode]+=stoneValue[start];
}
else if(n-start==2){
record[mode]+=stoneValue[start];
if(stoneValue[start+1]>0){
record[mode]+=stoneValue[start+1];
}
else{
record[other_mode]+=stoneValue[start+1];
}
}
else if(n-start>=3){
int best_diff=-INT_MAX;
int best_record[2];
record[0]=record[1]=0;
select(stoneValue,start+1,other_mode);
record[mode]+=stoneValue[start];
if(record[mode]-record[other_mode]>best_diff){
best_diff=record[mode]-record[other_mode];
best_record[0]=record[0];
best_record[1]=record[1];
}
record[0]=record[1]=0;
select(stoneValue,start+2,other_mode);
record[mode]+=stoneValue[start];
record[mode]+=stoneValue[start+1];
if(record[mode]-record[other_mode]>best_diff){
best_diff=record[mode]-record[other_mode];
best_record[0]=record[0];
best_record[1]=record[1];
}
record[0]=record[1]=0;
select(stoneValue,start+3,other_mode);
record[mode]+=stoneValue[start];
record[mode]+=stoneValue[start+1];
record[mode]+=stoneValue[start+2];
if(record[mode]-record[other_mode]>best_diff){
best_diff=record[mode]-record[other_mode];
best_record[0]=record[0];
best_record[1]=record[1];
}
record[0]=best_record[0];
record[1]=best_record[1];
}
cache[start][0]=record[mode];
cache[start][1]=record[other_mode];
}
string stoneGameIII(vector<int>& stoneValue) {
memset(cache,-1,sizeof(cache));
n=stoneValue.size();
record[0]=record[1]=0;
select(stoneValue,0,0);
if(record[0]>record[1])
return "Alice";
else if(record[0]<record[1])
return "Bob";
else
return "Tie";
}
};
方法二:动态规划
dp[i],从位置i开始能得到的最好分数,由于两个人的分数总和就是石头分数总和,用了一个前缀和,另一个人的分数就总和减去一个人的分数。
状态转移也是选择3种选择中最好的,已经选择的分数加上下一步自己的分数。
class Solution {
public:
int dp[50005];
int sum[50005];
string stoneGameIII(vector<int>& stoneValue) {
memset(dp,0,sizeof(dp));
memset(sum,0,sizeof(sum));
int n=stoneValue.size();
sum[0]=stoneValue[0];
for(int i=1;i<n;i++){
sum[i]=sum[i-1]+stoneValue[i];
}
for(int i=n-1;i>=0;i--){
dp[i]=stoneValue[i]+sum[n-1]-sum[i]-(i+1>=n?0:dp[i+1]);
if(i+1<n)
dp[i]=max(dp[i],stoneValue[i]+stoneValue[i+1]+sum[n-1]-sum[i+1]-(i+2>=n?0:dp[i+2]));
if(i+2<n)
dp[i]=max(dp[i],stoneValue[i]+stoneValue[i+1]+stoneValue[i+2]+sum[n-1]-sum[i+2]-(i+3>=n?0:dp[i+3]));
}
if(dp[0]>sum[n-1]-dp[0])
return "Alice";
else if(dp[0]<sum[n-1]-dp[0])
return "Bob";
else
return "Tie";
}
};